diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 660b089..fb6a30e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,7 @@ jobs: - name: Build run: | docker run --rm -v $PWD:/project -w /project espressif/idf:$IDF_VERSION /bin/bash -c "git config --global --add safe.directory /project && idf.py -DBOARD=${{ matrix.board }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} build" - python combine.py + # combine.py is auto run as postbuild if [ "${{ matrix.build_type }}" == "Debug" ]; then # add debug suffix to the bin file mv NINA_ADAFRUIT*.bin "$(echo NINA_ADAFRUIT*.bin | sed 's/.bin/_Debug.bin/')" diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f3c3aa..45a0f1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,16 +10,14 @@ else () message(FATAL_ERROR "Unsupported BOARD: ${BOARD}. Supported boards are: fruitjam_c6, esp32") endif () -# SDKCONFIG & SDKCONFIG_DEFAULTS for each target -set(SDKCONFIG ${CMAKE_SOURCE_DIR}/sdkconfig.${IDF_TARGET}) - # caused by esp-idf/components/bt/controller/esp32c6/bt.c:253:11: In function 'esp_bt_controller_log_init': # error: 'task_create' may be used uninitialized [-Werror=maybe-uninitialized] if (IDF_TARGET STREQUAL "esp32c6") add_compile_options(-Wno-maybe-uninitialized) endif () -set(SDKCONFIG_DEFAULTS sdkconfig.defaults sdkconfig.defaults.${BOARD}) +set(SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig) +set(SDKCONFIG_DEFAULTS sdkconfig.defaults ${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/sdkconfig) if (CMAKE_BUILD_TYPE STREQUAL "Debug") list(APPEND SDKCONFIG_DEFAULTS sdkconfig.debug) endif () @@ -34,5 +32,13 @@ STRING(TOUPPER ${BOARD} BOARD_UPPER) add_compile_definitions( BOARD_${BOARD_UPPER} ) +set(EXTRA_COMPONENT_DIRS ${CMAKE_CURRENT_LIST_DIR}/boards) project(nina-fw) + +# Post build to run combine.py +add_custom_command(TARGET app POST_BUILD + COMMAND python ${CMAKE_CURRENT_LIST_DIR}/combine.py -b ${CMAKE_BINARY_DIR} NINA_ADAFRUIT-${BOARD} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + VERBATIM + ) \ No newline at end of file diff --git a/boards/CMakeLists.txt b/boards/CMakeLists.txt new file mode 100644 index 0000000..bb0a5f8 --- /dev/null +++ b/boards/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register( + INCLUDE_DIRS . ${BOARD} + ) diff --git a/boards/esp32/board.h b/boards/esp32/board.h new file mode 100644 index 0000000..0592a7e --- /dev/null +++ b/boards/esp32/board.h @@ -0,0 +1,18 @@ +#ifndef BOARD_H +#define BOARD_H + +// SPIS for WiFi +#define AIRLIFT_MOSI 14 +#define AIRLIFT_MISO 23 +#define AIRLIFT_SCK 18 +#define AIRLIFT_CS 5 +#define AIRLIFT_BUSY 33 // ready + +// UART for BLE HCI +#define AIRLIFT_RTS AIRLIFT_BUSY +#define AIRLIFT_CTS 0 // BOOT PIN + +// #define CONFIG_BT_LE_HCI_UART_RTS_PIN 33 // ESP_BUSY (ready) +// #define CONFIG_BT_LE_HCI_UART_CTS_PIN 0 // GPIO0 + +#endif diff --git a/sdkconfig.defaults.esp32 b/boards/esp32/sdkconfig similarity index 100% rename from sdkconfig.defaults.esp32 rename to boards/esp32/sdkconfig diff --git a/boards/fruitjam_c6/board.h b/boards/fruitjam_c6/board.h new file mode 100644 index 0000000..bccf85f --- /dev/null +++ b/boards/fruitjam_c6/board.h @@ -0,0 +1,11 @@ +#ifndef BOARD_H +#define BOARD_H + +// SPIS for WiFi +#define AIRLIFT_MOSI 21 +#define AIRLIFT_MISO 6 +#define AIRLIFT_SCK 22 +#define AIRLIFT_CS 7 +#define AIRLIFT_BUSY CONFIG_BT_LE_HCI_UART_RTS_PIN // ready + +#endif diff --git a/sdkconfig.defaults.fruitjam_c6 b/boards/fruitjam_c6/sdkconfig similarity index 100% rename from sdkconfig.defaults.fruitjam_c6 rename to boards/fruitjam_c6/sdkconfig diff --git a/combine.py b/combine.py index e29f7af..1ea90c1 100644 --- a/combine.py +++ b/combine.py @@ -1,9 +1,9 @@ #!/usr/bin/env python import json -import re import sys - +import argparse +import os def extract_firmware_version(): with open('main/CommandHandler.cpp', 'r') as file: @@ -15,72 +15,83 @@ def extract_firmware_version(): return version raise RuntimeError("FIRMWARE_VERSION not found in CommandHandler.cpp") -def get_idf_target(): - with open("build/config.env") as file: +def get_idf_target(build_dir): + with open(f"{build_dir}/config.env") as file: config = json.load(file) return config["IDF_TARGET"] -bootloaderData = open("build/bootloader/bootloader.bin", "rb").read() -partitionData = open("build/partition_table/partition-table.bin", "rb").read() -#phyData = open("data/phy.bin", "rb").read() -appData = open("build/nina-fw.bin", "rb").read() +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('outfile', help='output file') + parser.add_argument('-b', '--build_dir', default='build', help='build directory') -# remove everything between certificate markers to save space. There might be comments and other information. -certsData = b"" -with open("certificates/data/roots.pem", "rb") as certs_file: - in_cert = False - for line in certs_file: - if line.startswith(b"-----BEGIN CERTIFICATE-----"): - in_cert = True - if in_cert: - certsData += line - if line.startswith(b"-----END CERTIFICATE-----"): - in_cert = False + args = parser.parse_args() + outfile = args.outfile + build_dir = os.path.normpath(args.build_dir) -# calculate the output binary size, app offset -outputSize = 0x30000 + len(appData) -if outputSize % 1024: - outputSize += 1024 - (outputSize % 1024) + bootloaderData = open(f"{build_dir}/bootloader/bootloader.bin", "rb").read() + partitionData = open(f"{build_dir}/partition_table/partition-table.bin", "rb").read() + #phyData = open("data/phy.bin", "rb").read() + appData = open(f"{build_dir}/nina-fw.bin", "rb").read() -# allocate and init to 0xff -outputData = bytearray(b"\xff") * outputSize + # remove everything between certificate markers to save space. There might be comments and other information. + certsData = b"" + with open("certificates/data/roots.pem", "rb") as certs_file: + in_cert = False + for line in certs_file: + if line.startswith(b"-----BEGIN CERTIFICATE-----"): + in_cert = True + if in_cert: + certsData += line + if line.startswith(b"-----END CERTIFICATE-----"): + in_cert = False -# copy data: bootloader, partitions, app -BOOTLOADER_OFFSET = { - "esp32" : 0x1000, - "esp32c6" : 0x0000, - } + # calculate the output binary size, app offset + outputSize = 0x30000 + len(appData) + if outputSize % 1024: + outputSize += 1024 - (outputSize % 1024) -try: - target = get_idf_target() - bootloader_offset = BOOTLOADER_OFFSET[get_idf_target()] -except KeyError: - raise RuntimeError(f"unsupported IDF_TARGET: {target}") + # allocate and init to 0xff + outputData = bytearray(b"\xff") * outputSize -for i in range(0, len(bootloaderData)): - outputData[bootloader_offset + i] = bootloaderData[i] + # copy data: bootloader, partitions, app + BOOTLOADER_OFFSET = { + "esp32" : 0x1000, + "esp32c6" : 0x0000, + } -for i in range(0, len(partitionData)): - outputData[0x8000 + i] = partitionData[i] + try: + idf_target = get_idf_target(build_dir) + bootloader_offset = BOOTLOADER_OFFSET[idf_target] + except KeyError: + raise RuntimeError(f"unsupported IDF_TARGET: {idf_target}") -#for i in range(0, len(phyData)): -# outputData[0xf000 + i] = phyData[i] + for i in range(0, len(bootloaderData)): + outputData[bootloader_offset + i] = bootloaderData[i] -for i in range(0, len(certsData)): - outputData[0x10000 + i] = certsData[i] + for i in range(0, len(partitionData)): + outputData[0x8000 + i] = partitionData[i] -# zero terminate the pem file -outputData[0x10000 + len(certsData)] = 0 + #for i in range(0, len(phyData)): + # outputData[0xf000 + i] = phyData[i] -for i in range(0, len(appData)): - outputData[0x30000 + i] = appData[i] + for i in range(0, len(certsData)): + outputData[0x10000 + i] = certsData[i] -version = extract_firmware_version() -outputFilename = f"NINA_ADAFRUIT-{target}-{version}.bin" -if len(sys.argv) > 1: - outputFilename = sys.argv[1] + # zero terminate the pem file + outputData[0x10000 + len(certsData)] = 0 -# write out -with open(outputFilename, "w+b") as f: - f.seek(0) - f.write(outputData) + for i in range(0, len(appData)): + outputData[0x30000 + i] = appData[i] + + version = extract_firmware_version() + outputFilename = f"{outfile}-{version}.bin" + + # write out + with open(outputFilename, "w+b") as f: + f.seek(0) + f.write(outputData) + + +if __name__ == '__main__': + main() diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 10979e4..d1b8b21 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRCS CommandHandler.cpp http_client.c sketch.ino.cpp - REQUIRES bt esp_http_client spiffs SPIS + REQUIRES bt esp_http_client spiffs SPIS boards PRIV_INCLUDE_DIRS "." INCLUDE_DIRS "." $ENV{IDF_PATH}/components/esp_netif ) diff --git a/main/sketch.ino.cpp b/main/sketch.ino.cpp index f5fe082..22b93fe 100644 --- a/main/sketch.ino.cpp +++ b/main/sketch.ino.cpp @@ -51,60 +51,41 @@ int debug = 1; //-------------------------------------------------------------------- // ADAFRUIT CHANGE //-------------------------------------------------------------------- + +// contains SPIS and BT/BLE UART pin definitions +#if !__has_include("board.h") +#error "Board is not supported, please add -DBOARD= to the build command" +#endif + +#include "board.h" + #define AIRLIFT 1 // Adafruit Airlift #define NINA_PRINTF(...) do { if (debug) { ets_printf(__VA_ARGS__); } } while (0) #if defined(CONFIG_IDF_TARGET_ESP32) -// SPIS for WiFi -#define AIRLIFT_MOSI 14 -#define AIRLIFT_MISO 23 -#define AIRLIFT_SCK 18 -#define AIRLIFT_CS 5 -#define AIRLIFT_BUSY 33 // ready + extern const struct __sFILE_fake __sf_fake_stdin; + extern const struct __sFILE_fake __sf_fake_stdout; + extern const struct __sFILE_fake __sf_fake_stderr; -// UART for BLE HCI -#define AIRLIFT_RTS AIRLIFT_BUSY -#define AIRLIFT_CTS 0 // BOOT PIN - -// #define CONFIG_BT_LE_HCI_UART_RTS_PIN 33 // ESP_BUSY (ready) -// #define CONFIG_BT_LE_HCI_UART_CTS_PIN 0 // GPIO0 - -extern const struct __sFILE_fake __sf_fake_stdin; -extern const struct __sFILE_fake __sf_fake_stdout; -extern const struct __sFILE_fake __sf_fake_stderr; - -// dev, dma, mosi, miso, sclk, cs, ready -SPISClass SPIS(VSPI_HOST, 1, AIRLIFT_MOSI, AIRLIFT_MISO, AIRLIFT_SCK, AIRLIFT_CS, AIRLIFT_BUSY); + // dev, dma, mosi, miso, sclk, cs, ready + SPISClass SPIS(VSPI_HOST, 1, AIRLIFT_MOSI, AIRLIFT_MISO, AIRLIFT_SCK, AIRLIFT_CS, AIRLIFT_BUSY); #endif #if defined(CONFIG_IDF_TARGET_ESP32C6) + // UART for BLE HCI + // CONFIG_BT_LE_HCI_UART_RTS_PIN and CONFIG_BT_LE_HCI_UART_CTS_PIN are defined in boards/{BOARD}/sdkconfig + // and used by hci_driver_uart_config() in hci_driver_uart.c. It should matches with BUSY and BOOT pins. + #ifndef CONFIG_BT_LE_HCI_INTERFACE_USE_UART + #error "Please Enable Uart for HCI" + #endif -// UART for BLE HCI -// CONFIG_BT_LE_HCI_UART_RTS_PIN and CONFIG_BT_LE_HCI_UART_CTS_PIN are defined in sdkconfig.defaults.BOARD -// and used by hci_driver_uart_config() in hci_driver_uart.c. It should matches with BUSY and BOOT pins. -#ifndef CONFIG_BT_LE_HCI_INTERFACE_USE_UART -#error "Please Enable Uart for HCI" -#endif + #if CONFIG_BT_LE_HCI_UART_CTS_PIN != 9 + #error "CTS pin must be the same as BOOT pin" + #endif -#if CONFIG_BT_LE_HCI_UART_CTS_PIN != 9 -#error "CTS pin must be the same as BOOT pin" -#endif - -// SPIS for WiFi -#define AIRLIFT_BUSY CONFIG_BT_LE_HCI_UART_RTS_PIN // ready - -#if defined(BOARD_FRUITJAM_C6) - #define AIRLIFT_MOSI 21 - #define AIRLIFT_MISO 6 - #define AIRLIFT_SCK 22 - #define AIRLIFT_CS 7 -#else - #error "Board is not supported, please add -DBOARD= to the build command" -#endif - -// dev, dma, mosi, miso, sclk, cs, ready -SPISClass SPIS(SPI2_HOST, SPI_DMA_CH_AUTO, - AIRLIFT_MOSI, AIRLIFT_MISO, AIRLIFT_SCK, AIRLIFT_CS, AIRLIFT_BUSY); + // dev, dma, mosi, miso, sclk, cs, ready + SPISClass SPIS(SPI2_HOST, SPI_DMA_CH_AUTO, + AIRLIFT_MOSI, AIRLIFT_MISO, AIRLIFT_SCK, AIRLIFT_CS, AIRLIFT_BUSY); #endif // prevent initArduino() to release BT memory