diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 49afcdc29..b5948811b 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -13,6 +13,10 @@ on: # * * * * * - cron: '0 */6 * * *' +defaults: + run: + shell: bash + jobs: run: name: Build with IDF ${{ matrix.idf_branch }} @@ -22,7 +26,7 @@ jobs: matrix: idf_branch: [release/v5.1, release/v4.4] #, release/v3.3] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Install dependencies run: bash ./tools/prepare-ci.sh - name: Build @@ -31,9 +35,101 @@ jobs: GIT_AUTHOR_EMAIL: ${{ secrets.PUSH_EMAIL }} GIT_COMMITTER_EMAIL: ${{ secrets.PUSH_EMAIL }} IDF_BRANCH: ${{ matrix.idf_branch }} - run: bash ./tools/cron.sh + run: | + git checkout ${{ matrix.idf_branch }} + bash ./tools/cron.sh - name: Upload archive - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 with: name: artifacts path: dist + + + # check: + # name: Check if result should be deployed + # runs-on: ubuntu-latest + # strategy: + # matrix: + # branch: [release/v5.1, release/v4.4] #, release/v3.3] + # outputs: + # idf_branch: ${{ steps.check.outputs.idf_branch }} + # idf_commit: ${{ steps.check.outputs.idf_commit }} + # ar_branch: ${{ steps.check.outputs.ar_branch }} + # ar_new_commit_message: ${{ steps.check.outputs.ar_new_commit_message }} + # ar_new_branch_name: ${{ steps.check.outputs.ar_new_branch_name }} + # ar_new_pr_title: ${{ steps.check.outputs.ar_new_pr_title }} + # ar_has_commit: ${{ steps.check.outputs.ar_has_commit }} + # ar_has_branch: ${{ steps.check.outputs.ar_has_branch }} + # ar_has_pr: ${{ steps.check.outputs.ar_has_pr }} + # libs_version: ${{ steps.check.outputs.libs_version }} + # libs_has_commit: ${{ steps.check.outputs.libs_has_commit }} + # libs_has_branch: ${{ steps.check.outputs.libs_has_branch }} + # steps: + # - uses: actions/checkout@v3 + # - id: check + # env: + # GITHUB_TOKEN: ${{ secrets.PUSH_TOKEN }} + # GIT_AUTHOR_EMAIL: ${{ secrets.PUSH_EMAIL }} + # GIT_COMMITTER_EMAIL: ${{ secrets.PUSH_EMAIL }} + # IDF_BRANCH: ${{ matrix.idf_branch }} + # run: bash ./tools/check-deploy-needed.sh + + # build: + # name: Build Libs for ${{ matrix.target }} + # runs-on: ubuntu-latest + # needs: check + # if: needs.check.outputs.libs_has_commit == '0' || needs.check.outputs.ar_has_commit == '0' + # strategy: + # matrix: + # target: [esp32, esp32s2, esp32s3, esp32c3, esp32c6, esp32h2] + # fail-fast: false + # steps: + # - uses: actions/checkout@v3 + # # - name: Install dependencies + # # run: bash ./tools/prepare-ci.sh + # - shell: bash + # name: Build Libs for ${{ matrix.target }} + # run: echo ${{ matrix.target }} + # # run: bash ./build.sh -t ${{ matrix.target }} + # # - name: Upload archive + # # uses: actions/upload-artifact@v3 + # # with: + # # name: artifacts + # # path: dist + + # deploy: + # name: Deploy build + # runs-on: ubuntu-latest + # needs: [check, build] + # steps: + # - uses: actions/checkout@v3 + # - shell: bash + # env: + # GITHUB_TOKEN: ${{ secrets.PUSH_TOKEN }} + # GIT_AUTHOR_EMAIL: ${{ secrets.PUSH_EMAIL }} + # GIT_COMMITTER_EMAIL: ${{ secrets.PUSH_EMAIL }} + # IDF_BRANCH: ${{ needs.check.outputs.idf_branch }} + # IDF_COMMIT: ${{ needs.check.outputs.idf_commit }} + # AR_BRANCH: ${{ needs.check.outputs.ar_branch }} + # AR_NEW_COMMIT_MESSAGE: ${{ needs.check.outputs.ar_new_commit_message }} + # AR_NEW_BRANCH_NAME: ${{ needs.check.outputs.ar_new_branch_name }} + # AR_NEW_PR_TITLE: ${{ needs.check.outputs.ar_new_pr_title }} + # AR_HAS_COMMIT: ${{ needs.check.outputs.ar_has_commit }} + # AR_HAS_BRANCH: ${{ needs.check.outputs.ar_has_branch }} + # AR_HAS_PR: ${{ needs.check.outputs.ar_has_pr }} + # LIBS_VERSION: ${{ needs.check.outputs.libs_version }} + # LIBS_HAS_COMMIT: ${{ needs.check.outputs.libs_has_commit }} + # LIBS_HAS_BRANCH: ${{ needs.check.outputs.libs_has_branch }} + # run: | + # echo "IDF_COMMIT: $IDF_COMMIT" + # echo "AR_BRANCH: $AR_BRANCH" + # echo "AR_NEW_COMMIT_MESSAGE: $AR_NEW_COMMIT_MESSAGE" + # echo "AR_NEW_BRANCH_NAME: $AR_NEW_BRANCH_NAME" + # echo "AR_NEW_PR_TITLE: $AR_NEW_PR_TITLE" + # echo "AR_HAS_COMMIT: $AR_HAS_COMMIT" + # echo "AR_HAS_BRANCH: $AR_HAS_BRANCH" + # echo "AR_HAS_PR: $AR_HAS_PR" + # echo "LIBS_VERSION: $LIBS_VERSION" + # echo "LIBS_HAS_COMMIT: $LIBS_HAS_COMMIT" + # echo "LIBS_HAS_BRANCH: $LIBS_HAS_BRANCH" + diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index b461e3b17..56cc7e9f7 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -11,21 +11,50 @@ concurrency: cancel-in-progress: true jobs: + build-libs: name: Build Libs for ${{ matrix.target }} runs-on: ubuntu-latest strategy: matrix: - target: [esp32, esp32s2, esp32s3, esp32c3] + target: [esp32, esp32s2, esp32s3, esp32c3, esp32c6, esp32h2] fail-fast: false steps: - uses: actions/checkout@v3 - name: Install dependencies run: bash ./tools/prepare-ci.sh - name: Build Libs for ${{ matrix.target }} - run: bash ./build.sh -t ${{ matrix.target }} + run: bash ./build.sh -e -t ${{ matrix.target }} - name: Upload archive - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 with: - name: artifacts-${{ matrix.target }} + name: artifacts path: dist + + combine-artifacts: + name: Combine artifacts + needs: build-libs + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: artifacts + path: dist + - shell: bash + run: | + mkdir -p out + find dist -name 'arduino-esp32-libs-esp*.tar.gz' -exec tar zxvf {} -C out \; + cd out/tools/esp32-arduino-libs && tar zcf ../../../dist/esp32-arduino-libs.tar.gz * && cd ../../.. + cp out/package_esp32_index.template.json dist/package_esp32_index.template.json + - name: Upload full esp32-arduino-libs archive + uses: actions/upload-artifact@v3 + with: + name: esp32-arduino-libs + path: dist/esp32-arduino-libs.tar.gz + - name: Upload package_esp32_index.template.json + uses: actions/upload-artifact@v3 + with: + name: package-esp32-index-json + path: dist/package_esp32_index.template.json + diff --git a/.github/workflows/repository_dispatch.yml b/.github/workflows/repository_dispatch.yml index 016b84831..678deb4e8 100644 --- a/.github/workflows/repository_dispatch.yml +++ b/.github/workflows/repository_dispatch.yml @@ -7,7 +7,7 @@ jobs: name: Dispatch Event runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Install dependencies run: bash ./tools/prepare-ci.sh - name: Handle Event @@ -17,7 +17,7 @@ jobs: GIT_COMMITTER_EMAIL: ${{ secrets.PUSH_EMAIL }} run: bash ./tools/repository_dispatch.sh - name: Upload archive - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 with: name: artifacts path: dist diff --git a/.gitignore b/.gitignore index 4cd4f7804..b0749543f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ components/esp-rainmaker/ components/espressif__esp-dsp/ components/esp-insights/ components/arduino_tinyusb/tinyusb/ +components/tflite-micro/ esp-idf/ out/ build/ @@ -19,3 +20,5 @@ sdkconfig sdkconfig.old version.txt dependencies.lock +managed_components/ +target/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 558857ce5..f0d4f40d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,10 @@ cmake_minimum_required(VERSION 3.5) set(RMAKER_PATH ${CMAKE_SOURCE_DIR}/components/esp-rainmaker) -set(EXTRA_COMPONENT_DIRS ${RMAKER_PATH}/components/esp-insights/components ${RMAKER_PATH}/components ${CMAKE_SOURCE_DIR}/components/esp-insights/components) +set(INSIGHTS_PATH ${RMAKER_PATH}/components/esp-insights) +set(TFLITE_PATH ${CMAKE_SOURCE_DIR}/components/tflite-micro) + +set(EXTRA_COMPONENT_DIRS ${INSIGHTS_PATH}/components ${RMAKER_PATH}/components ${TFLITE_PATH}/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(arduino-lib-builder) @@ -13,7 +16,7 @@ idf_build_get_property(elf EXECUTABLE GENERATOR_EXPRESSION) add_custom_command( OUTPUT "idf_libs" COMMAND ${CMAKE_SOURCE_DIR}/tools/copy-libs.sh ${IDF_TARGET} "${CONFIG_LIB_BUILDER_FLASHMODE}" "${CONFIG_SPIRAM_MODE_OCT}" "${CONFIG_IDF_TARGET_ARCH_XTENSA}" - DEPENDS ${elf} + DEPENDS all WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} VERBATIM ) diff --git a/build.sh b/build.sh index 7e4b1c190..5987b78b3 100755 --- a/build.sh +++ b/build.sh @@ -14,14 +14,18 @@ TARGET="all" BUILD_TYPE="all" SKIP_ENV=0 COPY_OUT=0 -DEPLOY_OUT=0 +ARCHIVE_OUT=0 +if [ -z $DEPLOY_OUT ]; then + DEPLOY_OUT=0 +fi function print_help() { - echo "Usage: build.sh [-s] [-A ] [-I ] [-i ] [-c ] [-t ] [-b ] [config ...]" + echo "Usage: build.sh [-s] [-A ] [-I ] [-i ] [-c ] [-t ] [-b ] [config ...]" echo " -s Skip installing/updating of ESP-IDF and all components" echo " -A Set which branch of arduino-esp32 to be used for compilation" echo " -I Set which branch of ESP-IDF to be used for compilation" echo " -i Set which commit of ESP-IDF to be used for compilation" + echo " -e Archive the build to dist" echo " -d Deploy the build to github arduino-esp32" echo " -c Set the arduino-esp32 folder to copy the result to. ex. '$HOME/Arduino/hardware/espressif/esp32'" echo " -t Set the build target(chip). ex. 'esp32s3'" @@ -30,7 +34,7 @@ function print_help() { exit 1 } -while getopts ":A:I:i:c:t:b:sd" opt; do +while getopts ":A:I:i:c:t:b:sde" opt; do case ${opt} in s ) SKIP_ENV=1 @@ -38,6 +42,9 @@ while getopts ":A:I:i:c:t:b:sd" opt; do d ) DEPLOY_OUT=1 ;; + e ) + ARCHIVE_OUT=1 + ;; c ) export ESP32_ARDUINO="$OPTARG" COPY_OUT=1 @@ -58,6 +65,7 @@ while getopts ":A:I:i:c:t:b:sd" opt; do b=$OPTARG if [ "$b" != "build" ] && [ "$b" != "menuconfig" ] && + [ "$b" != "reconfigure" ] && [ "$b" != "idf_libs" ] && [ "$b" != "copy_bootloader" ] && [ "$b" != "mem_variant" ]; then @@ -78,19 +86,31 @@ done shift $((OPTIND -1)) CONFIGS=$@ +mkdir -p dist + if [ $SKIP_ENV -eq 0 ]; then echo "* Installing/Updating ESP-IDF and all components..." # update components from git ./tools/update-components.sh if [ $? -ne 0 ]; then exit 1; fi + # install arduino component + ./tools/install-arduino.sh + if [ $? -ne 0 ]; then exit 1; fi + # install esp-idf source ./tools/install-esp-idf.sh if [ $? -ne 0 ]; then exit 1; fi else + # $IDF_PATH/install.sh + # source $IDF_PATH/export.sh source ./tools/config.sh fi +if [ -f "./managed_components/espressif__esp-sr/.component_hash" ]; then + rm -rf ./managed_components/espressif__esp-sr/.component_hash +fi + if [ "$BUILD_TYPE" != "all" ]; then if [ "$TARGET" = "all" ]; then echo "ERROR: You need to specify target for non-default builds" @@ -123,17 +143,17 @@ fi rm -rf build sdkconfig out # Add components version info -mkdir -p "$AR_TOOLS/sdk" && rm -rf version.txt && rm -rf "$AR_TOOLS/sdk/versions.txt" +mkdir -p "$AR_TOOLS/esp32-arduino-libs" && rm -rf version.txt && rm -rf "$AR_TOOLS/esp32-arduino-libs/versions.txt" component_version="esp-idf: "$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD)" "$(git -C "$IDF_PATH" rev-parse --short HEAD) -echo $component_version >> version.txt && echo $component_version >> "$AR_TOOLS/sdk/versions.txt" +echo $component_version >> version.txt && echo $component_version >> "$AR_TOOLS/esp32-arduino-libs/versions.txt" for component in `ls "$AR_COMPS"`; do if [ -d "$AR_COMPS/$component/.git" ] || [ -d "$AR_COMPS/$component/.github" ]; then component_version="$component: "$(git -C "$AR_COMPS/$component" symbolic-ref --short HEAD || git -C "$AR_COMPS/$component" tag --points-at HEAD)" "$(git -C "$AR_COMPS/$component" rev-parse --short HEAD) - echo $component_version >> version.txt && echo $component_version >> "$AR_TOOLS/sdk/versions.txt" + echo $component_version >> version.txt && echo $component_version >> "$AR_TOOLS/esp32-arduino-libs/versions.txt" fi done component_version="tinyusb: "$(git -C "$AR_COMPS/arduino_tinyusb/tinyusb" symbolic-ref --short HEAD || git -C "$AR_COMPS/arduino_tinyusb/tinyusb" tag --points-at HEAD)" "$(git -C "$AR_COMPS/arduino_tinyusb/tinyusb" rev-parse --short HEAD) -echo $component_version >> version.txt && echo $component_version >> "$AR_TOOLS/sdk/versions.txt" +echo $component_version >> version.txt && echo $component_version >> "$AR_TOOLS/esp32-arduino-libs/versions.txt" #targets_count=`jq -c '.targets[] | length' configs/builds.json` for target_json in `jq -c '.targets[]' configs/builds.json`; do @@ -157,6 +177,11 @@ for target_json in `jq -c '.targets[]' configs/builds.json`; do for defconf in `echo "$target_json" | jq -c '.idf_libs[]' | tr -d '"'`; do idf_libs_configs="$idf_libs_configs;configs/defconfig.$defconf" done + + if [ -f "./managed_components/espressif__esp-sr/.component_hash" ]; then + rm -rf ./managed_components/espressif__esp-sr/.component_hash + fi + echo "* Build IDF-Libs: $idf_libs_configs" rm -rf build sdkconfig idf.py -DIDF_TARGET="$target" -DSDKCONFIG_DEFAULTS="$idf_libs_configs" idf_libs @@ -168,6 +193,11 @@ for target_json in `jq -c '.targets[]' configs/builds.json`; do for defconf in `echo "$boot_conf" | jq -c '.[]' | tr -d '"'`; do bootloader_configs="$bootloader_configs;configs/defconfig.$defconf"; done + + if [ -f "./managed_components/espressif__esp-sr/.component_hash" ]; then + rm -rf ./managed_components/espressif__esp-sr/.component_hash + fi + echo "* Build BootLoader: $bootloader_configs" rm -rf build sdkconfig idf.py -DIDF_TARGET="$target" -DSDKCONFIG_DEFAULTS="$bootloader_configs" copy_bootloader @@ -180,6 +210,11 @@ for target_json in `jq -c '.targets[]' configs/builds.json`; do for defconf in `echo "$mem_conf" | jq -c '.[]' | tr -d '"'`; do mem_configs="$mem_configs;configs/defconfig.$defconf"; done + + if [ -f "./managed_components/espressif__esp-sr/.component_hash" ]; then + rm -rf ./managed_components/espressif__esp-sr/.component_hash + fi + echo "* Build Memory Variant: $mem_configs" rm -rf build sdkconfig idf.py -DIDF_TARGET="$target" -DSDKCONFIG_DEFAULTS="$mem_configs" mem_variant @@ -190,20 +225,30 @@ done # update package_esp32_index.template.json if [ "$BUILD_TYPE" = "all" ]; then python3 ./tools/gen_tools_json.py -i "$IDF_PATH" -j "$AR_COMPS/arduino/package/package_esp32_index.template.json" -o "$AR_OUT/" + python3 ./tools/gen_tools_json.py -i "$IDF_PATH" -o "$TOOLS_JSON_OUT/" if [ $? -ne 0 ]; then exit 1; fi fi -# archive the build +# Generate PlatformIO manifest file if [ "$BUILD_TYPE" = "all" ]; then - ./tools/archive-build.sh + python3 ./tools/gen_platformio_manifest.py -o "$TOOLS_JSON_OUT/" -s $(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD) -c $(git -C "$IDF_PATH" rev-parse --short HEAD) if [ $? -ne 0 ]; then exit 1; fi fi # copy everything to arduino-esp32 installation if [ $COPY_OUT -eq 1 ] && [ -d "$ESP32_ARDUINO" ]; then ./tools/copy-to-arduino.sh + if [ $? -ne 0 ]; then exit 1; fi fi +# push changes to esp32-arduino-libs and create pull request into arduino-esp32 if [ $DEPLOY_OUT -eq 1 ]; then ./tools/push-to-arduino.sh + if [ $? -ne 0 ]; then exit 1; fi +fi + +# archive the build +if [ $ARCHIVE_OUT -eq 1 ]; then + ./tools/archive-build.sh "$TARGET" + if [ $? -ne 0 ]; then exit 1; fi fi diff --git a/components/arduino_tinyusb/CMakeLists.txt b/components/arduino_tinyusb/CMakeLists.txt index 041eeec0f..792b2a39f 100755 --- a/components/arduino_tinyusb/CMakeLists.txt +++ b/components/arduino_tinyusb/CMakeLists.txt @@ -1,62 +1,74 @@ -idf_component_register(REQUIRES esp_rom freertos soc PRIV_REQUIRES arduino main) - if(CONFIG_TINYUSB_ENABLED) ### variables ### ################# - # if(IDF_TARGET STREQUAL "esp32s2") + + if(IDF_TARGET STREQUAL "esp32s2") set(compile_options "-DCFG_TUSB_MCU=OPT_MCU_ESP32S2" "-DCFG_TUSB_DEBUG=${CONFIG_TINYUSB_DEBUG_LEVEL}" "-Wno-type-limits" # needed for the vanila tinyusb with turned off classes ) - # elseif(IDF_TARGET STREQUAL "esp32s3") - # set(compile_options - # "-DCFG_TUSB_MCU=OPT_MCU_ESP32S2" - # "-DCFG_TUSB_DEBUG=${CONFIG_TINYUSB_DEBUG_LEVEL}" - # "-Wno-type-limits" # needed for the vanila tinyusb with turned off classes - # ) - # endif() - idf_component_get_property(FREERTOS_ORIG_INCLUDE_PATH freertos - ORIG_INCLUDE_PATH) - set(includes_private - # tusb: - "${COMPONENT_DIR}/tinyusb/hw/bsp/" - "${COMPONENT_DIR}/tinyusb/src/" - "${COMPONENT_DIR}/tinyusb/src/device" - ) + elseif(IDF_TARGET STREQUAL "esp32s3") + set(compile_options + "-DCFG_TUSB_MCU=OPT_MCU_ESP32S3" + "-DCFG_TUSB_DEBUG=${CONFIG_TINYUSB_DEBUG_LEVEL}" + "-Wno-type-limits" # needed for the vanila tinyusb with turned off classes + ) + endif() - set(includes_public - # tusb: - "${FREERTOS_ORIG_INCLUDE_PATH}" - "${COMPONENT_DIR}/tinyusb/src/" - # espressif: - "${COMPONENT_DIR}/include") set(srcs # espressif: "${COMPONENT_DIR}/src/dcd_esp32sx.c" + #"${COMPONENT_DIR}/src/dcd_dwc2.c" # tusb: #"${COMPONENT_DIR}/tinyusb/src/portable/espressif/esp32sx/dcd_esp32sx.c" + #"{COMPONENT_DIR}/tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c" "${COMPONENT_DIR}/tinyusb/src/class/cdc/cdc_device.c" "${COMPONENT_DIR}/tinyusb/src/class/hid/hid_device.c" "${COMPONENT_DIR}/tinyusb/src/class/midi/midi_device.c" "${COMPONENT_DIR}/tinyusb/src/class/msc/msc_device.c" "${COMPONENT_DIR}/tinyusb/src/class/video/video_device.c" "${COMPONENT_DIR}/tinyusb/src/class/dfu/dfu_rt_device.c" + "${COMPONENT_DIR}/tinyusb/src/class/dfu/dfu_device.c" "${COMPONENT_DIR}/tinyusb/src/class/vendor/vendor_device.c" "${COMPONENT_DIR}/tinyusb/src/common/tusb_fifo.c" "${COMPONENT_DIR}/tinyusb/src/device/usbd_control.c" "${COMPONENT_DIR}/tinyusb/src/device/usbd.c" "${COMPONENT_DIR}/tinyusb/src/tusb.c") + set(includes_private + # tusb: + "${COMPONENT_DIR}/tinyusb/hw/bsp/" + "${COMPONENT_DIR}/tinyusb/src/" + "${COMPONENT_DIR}/tinyusb/src/device" + "${COMPONENT_DIR}/tinyusb/src/portable/synopsys/dwc2" + ) + + idf_component_get_property(FREERTOS_ORIG_INCLUDE_PATH freertos + ORIG_INCLUDE_PATH) + set(includes_public + # tusb: + "${FREERTOS_ORIG_INCLUDE_PATH}" + "${COMPONENT_DIR}/tinyusb/src/" + # espressif: + "${COMPONENT_DIR}/include") + + set(requires esp_rom freertos soc) + set(priv_requires arduino main) ### tinyusb lib ### ################### - add_library(arduino_tinyusb STATIC ${srcs}) - target_include_directories( - arduino_tinyusb - PUBLIC ${includes_public} - PRIVATE ${includes_private}) - target_compile_options(arduino_tinyusb PRIVATE ${compile_options}) - target_link_libraries(${COMPONENT_TARGET} INTERFACE arduino_tinyusb) + idf_component_register(INCLUDE_DIRS ${includes_public} PRIV_INCLUDE_DIRS ${includes_private} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires}) + # add_library(${COMPONENT_TARGET} STATIC ${srcs}) + # target_include_directories( + # ${COMPONENT_TARGET} + # PUBLIC ${includes_public} + # PRIVATE ${includes_private}) + target_compile_options(${COMPONENT_TARGET} PRIVATE ${compile_options}) + #target_link_libraries(${COMPONENT_TARGET} INTERFACE ${COMPONENT_TARGET}) + +else() + + idf_component_register() endif() diff --git a/components/arduino_tinyusb/Kconfig.projbuild b/components/arduino_tinyusb/Kconfig.projbuild index a6abd4d8a..80983657f 100755 --- a/components/arduino_tinyusb/Kconfig.projbuild +++ b/components/arduino_tinyusb/Kconfig.projbuild @@ -175,6 +175,31 @@ menu "Arduino TinyUSB" endmenu + menu "DFU driver" + depends on TINYUSB_ENABLED + + config TINYUSB_DFU_ENABLED + bool "Enable USB DFU TinyUSB driver" + default y + help + Enable USB DFU TinyUSB driver. + + config TINYUSB_DESC_DFU_STRING + string "DFU Device String" + default "Espressif DFU Device" + depends on TINYUSB_DFU_ENABLED + help + Specify name of the DFU device + + config TINYUSB_DFU_BUFSIZE + int "DFU buffer size" + default 4096 + depends on TINYUSB_DFU_ENABLED + help + DFU buffer size + + endmenu + menu "VENDOR driver" depends on TINYUSB_ENABLED diff --git a/components/arduino_tinyusb/include/tusb_config.h b/components/arduino_tinyusb/include/tusb_config.h index a5a0afd32..ee1e5d270 100755 --- a/components/arduino_tinyusb/include/tusb_config.h +++ b/components/arduino_tinyusb/include/tusb_config.h @@ -64,6 +64,10 @@ extern "C" { # define CONFIG_TINYUSB_DFU_RT_ENABLED 0 #endif +#ifndef CONFIG_TINYUSB_DFU_ENABLED +# define CONFIG_TINYUSB_DFU_ENABLED 0 +#endif + #ifndef CONFIG_TINYUSB_VENDOR_ENABLED # define CONFIG_TINYUSB_VENDOR_ENABLED 0 #endif @@ -106,6 +110,7 @@ extern "C" { #define CFG_TUD_VIDEO CONFIG_TINYUSB_VIDEO_ENABLED #define CFG_TUD_CUSTOM_CLASS CONFIG_TINYUSB_CUSTOM_CLASS_ENABLED #define CFG_TUD_DFU_RUNTIME CONFIG_TINYUSB_DFU_RT_ENABLED +#define CFG_TUD_DFU CONFIG_TINYUSB_DFU_ENABLED #define CFG_TUD_VENDOR CONFIG_TINYUSB_VENDOR_ENABLED // CDC FIFO size of TX and RX @@ -126,6 +131,9 @@ extern "C" { #define CFG_TUD_VIDEO_STREAMING CONFIG_TINYUSB_VIDEO_STREAMING_IFS #define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE CONFIG_TINYUSB_VIDEO_STREAMING_BUFSIZE +// DFU buffer size +#define CFG_TUD_DFU_XFER_BUFSIZE CONFIG_TINYUSB_DFU_BUFSIZE + // VENDOR FIFO size of TX and RX #define CFG_TUD_VENDOR_RX_BUFSIZE CONFIG_TINYUSB_VENDOR_RX_BUFSIZE #define CFG_TUD_VENDOR_TX_BUFSIZE CONFIG_TINYUSB_VENDOR_TX_BUFSIZE diff --git a/components/arduino_tinyusb/src/dcd_dwc2.c b/components/arduino_tinyusb/src/dcd_dwc2.c new file mode 100644 index 000000000..67653fda0 --- /dev/null +++ b/components/arduino_tinyusb/src/dcd_dwc2.c @@ -0,0 +1,1389 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 William D. Jones + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * Copyright (c) 2020 Jan Duempelmann + * Copyright (c) 2020 Reinhard Panhuber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUD_ENABLED && defined(TUP_USBIP_DWC2) + +#include "device/dcd.h" +#include "dwc2_type.h" + +// Following symbols must be defined by port header +// - _dwc2_controller[]: array of controllers +// - DWC2_EP_MAX: largest EP counts of all controllers +// - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset +// - dwc2_dcd_int_enable/dwc2_dcd_int_disable +// - dwc2_remote_wakeup_delay + +#if defined(TUP_USBIP_DWC2_STM32) + #include "dwc2_stm32.h" +#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + #include "dwc2_esp32.h" +#elif TU_CHECK_MCU(OPT_MCU_GD32VF103) + #include "dwc2_gd32.h" +#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837) + #include "dwc2_bcm.h" +#elif TU_CHECK_MCU(OPT_MCU_EFM32GG) + #include "dwc2_efm32.h" +#elif TU_CHECK_MCU(OPT_MCU_XMC4000) + #include "dwc2_xmc.h" +#else + #error "Unsupported MCUs" +#endif + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM +//--------------------------------------------------------------------+ + +// DWC2 registers +#define DWC2_REG(_port) ((dwc2_regs_t*) _dwc2_controller[_port].reg_base) + +// Debug level for DWC2 +#define DWC2_DEBUG 2 + +#ifndef dcache_clean +#define dcache_clean(_addr, _size) +#endif + +#ifndef dcache_invalidate +#define dcache_invalidate(_addr, _size) +#endif + +#ifndef dcache_clean_invalidate +#define dcache_clean_invalidate(_addr, _size) +#endif + +static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[2]; + +typedef struct { + uint8_t * buffer; + tu_fifo_t * ff; + uint16_t total_len; + uint16_t max_size; + uint8_t interval; +} xfer_ctl_t; + +static xfer_ctl_t xfer_status[DWC2_EP_MAX][2]; +#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir]) + +// EP0 transfers are limited to 1 packet - larger sizes has to be split +static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type + +// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz +static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs) +static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size) + +// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by +static bool _sof_en; + +// Calculate the RX FIFO size according to recommendations from reference manual +static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) +{ + return 15 + 2*(max_ep_size/4) + 2*ep_count; +} + +static void update_grxfsiz(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // Determine largest EP size for RX FIFO + uint16_t max_epsize = 0; + for (uint8_t epnum = 0; epnum < ep_count; epnum++) + { + max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size); + } + + // Update size of RX FIFO + dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count); +} + +// Start of Bus Reset +static void bus_reset(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + tu_memclr(xfer_status, sizeof(xfer_status)); + _out_ep_closed = false; + + _sof_en = false; + + // clear device address + dwc2->dcfg &= ~DCFG_DAD_Msk; + + // 1. NAK for all OUT endpoints + for ( uint8_t n = 0; n < ep_count; n++ ) + { + dwc2->epout[n].doepctl |= DOEPCTL_SNAK; + } + + // 2. Set up interrupt mask + dwc2->daintmsk = TU_BIT(DAINTMSK_OEPM_Pos) | TU_BIT(DAINTMSK_IEPM_Pos); + dwc2->doepmsk = DOEPMSK_STUPM | DOEPMSK_XFRCM; + dwc2->diepmsk = DIEPMSK_TOM | DIEPMSK_XFRCM; + + // "USB Data FIFOs" section in reference manual + // Peripheral FIFO architecture + // + // The FIFO is split up in a lower part where the RX FIFO is located and an upper part where the TX FIFOs start. + // We do this to allow the RX FIFO to grow dynamically which is possible since the free space is located + // between the RX and TX FIFOs. This is required by ISO OUT EPs which need a bigger FIFO than the standard + // configuration done below. + // + // Dynamically FIFO sizes are of interest only for ISO EPs since all others are usually not opened and closed. + // All EPs other than ISO are opened as soon as the driver starts up i.e. when the host sends a + // configure interface command. Hence, all IN EPs other the ISO will be located at the top. IN ISO EPs are usually + // opened when the host sends an additional command: setInterface. At this point in time + // the ISO EP will be located next to the free space and can change its size. In case more IN EPs change its size + // an additional memory + // + // --------------- 320 or 1024 ( 1280 or 4096 bytes ) + // | IN FIFO 0 | + // --------------- (320 or 1024) - 16 + // | IN FIFO 1 | + // --------------- (320 or 1024) - 16 - x + // | . . . . | + // --------------- (320 or 1024) - 16 - x - y - ... - z + // | IN FIFO MAX | + // --------------- + // | FREE | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits): + // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN + // + // - All EP OUT shared a unique OUT FIFO which uses + // - 13 for setup packets + control words (up to 3 setup packets). + // - 1 for global NAK (not required/used here). + // - Largest-EPsize / 4 + 1. ( FS: 64 bytes, HS: 512 bytes). Recommended is "2 x (Largest-EPsize/4) + 1" + // - 2 for each used OUT endpoint + // + // Therefore GRXFSIZ = 13 + 1 + 1 + 2 x (Largest-EPsize/4) + 2 x EPOUTnum + // - FullSpeed (64 Bytes ): GRXFSIZ = 15 + 2 x 16 + 2 x ep_count = 47 + 2 x ep_count + // - Highspeed (512 bytes): GRXFSIZ = 15 + 2 x 128 + 2 x ep_count = 271 + 2 x ep_count + // + // NOTE: Largest-EPsize & EPOUTnum is actual used endpoints in configuration. Since DCD has no knowledge + // of the overall picture yet. We will use the worst scenario: largest possible + ep_count + // + // For Isochronous, largest EP size can be 1023/1024 for FS/HS respectively. In addition if multiple ISO + // are enabled at least "2 x (Largest-EPsize/4) + 1" are recommended. Maybe provide a macro for application to + // overwrite this. + + // EP0 out max is 64 + dwc2->grxfsiz = calc_grxfsiz(64, ep_count); + + // Setup the control endpoint 0 + _allocated_fifo_words_tx = 16; + + // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word ) + dwc2->dieptxf0 = (16 << DIEPTXF0_TX0FD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); + + // Fixed control EP0 size to 64 bytes + dwc2->epin[0].diepctl &= ~(0x03 << DIEPCTL_MPSIZ_Pos); + xfer_status[0][TUSB_DIR_OUT].max_size = 64; + xfer_status[0][TUSB_DIR_IN ].max_size = 64; + + dwc2->epout[0].doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); + + dwc2->gintmsk |= GINTMSK_OEPINT | GINTMSK_IEPINT; +} + +static void edpt_schedule_packets(uint8_t rhport, uint8_t const epnum, uint8_t const dir, uint16_t const num_packets, uint16_t total_bytes) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // EP0 is limited to one packet each xfer + // We use multiple transaction of xfer->max_size length to get a whole transfer done + if ( epnum == 0 ) + { + xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, dir); + total_bytes = tu_min16(ep0_pending[dir], xfer->max_size); + ep0_pending[dir] -= total_bytes; + } + + // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. + if ( dir == TUSB_DIR_IN ) + { + dwc2_epin_t* epin = dwc2->epin; + + // A full IN transfer (multiple packets, possibly) triggers XFRC. + epin[epnum].dieptsiz = (num_packets << DIEPTSIZ_PKTCNT_Pos) | + ((total_bytes << DIEPTSIZ_XFRSIZ_Pos) & DIEPTSIZ_XFRSIZ_Msk); + + epin[epnum].diepctl |= DIEPCTL_EPENA | DIEPCTL_CNAK; + + // For ISO endpoint set correct odd/even bit for next frame. + if ( (epin[epnum].diepctl & DIEPCTL_EPTYP) == DIEPCTL_EPTYP_0 && (XFER_CTL_BASE(epnum, dir))->interval == 1 ) + { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); + epin[epnum].diepctl |= (odd_frame_now ? DIEPCTL_SD0PID_SEVNFRM_Msk : DIEPCTL_SODDFRM_Msk); + } + // Enable fifo empty interrupt only if there are something to put in the fifo. + if ( total_bytes != 0 ) + { + dwc2->diepempmsk |= (1 << epnum); + } + } + else + { + dwc2_epout_t* epout = dwc2->epout; + + // A full OUT transfer (multiple packets, possibly) triggers XFRC. + epout[epnum].doeptsiz &= ~(DOEPTSIZ_PKTCNT_Msk | DOEPTSIZ_XFRSIZ); + epout[epnum].doeptsiz |= (num_packets << DOEPTSIZ_PKTCNT_Pos) | + ((total_bytes << DOEPTSIZ_XFRSIZ_Pos) & DOEPTSIZ_XFRSIZ_Msk); + + epout[epnum].doepctl |= DOEPCTL_EPENA | DOEPCTL_CNAK; + if ( (epout[epnum].doepctl & DOEPCTL_EPTYP) == DOEPCTL_EPTYP_0 && + XFER_CTL_BASE(epnum, dir)->interval == 1 ) + { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (dwc2->dsts & (1u << DSTS_FNSOF_Pos)); + epout[epnum].doepctl |= (odd_frame_now ? DOEPCTL_SD0PID_SEVNFRM_Msk : DOEPCTL_SODDFRM_Msk); + } + } +} + +/*------------------------------------------------------------------*/ +/* Controller API + *------------------------------------------------------------------*/ +#if CFG_TUSB_DEBUG >= DWC2_DEBUG +void print_dwc2_info(dwc2_regs_t * dwc2) +{ + dwc2_ghwcfg2_t const * hw_cfg2 = &dwc2->ghwcfg2_bm; + dwc2_ghwcfg3_t const * hw_cfg3 = &dwc2->ghwcfg3_bm; + dwc2_ghwcfg4_t const * hw_cfg4 = &dwc2->ghwcfg4_bm; + +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg); + TU_LOG_HEX(DWC2_DEBUG, dwc2->guid); + TU_LOG_HEX(DWC2_DEBUG, dwc2->gsnpsid); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg1); + + // HW configure 2 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg2); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->op_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->arch ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->point2point ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->hs_phy_type ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->fs_phy_type ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_dev_ep ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->num_host_ch ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->period_channel_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->enable_dynamic_fifo ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->mul_cpu_int ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->nperiod_tx_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->host_period_tx_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->dev_token_q_depth ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg2->otg_enable_ic_usb ); + + // HW configure 3 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg3); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->xfer_size_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->packet_size_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->i2c_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->vendor_ctrl_itf ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->optional_feature_removed ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->synch_reset ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_adp_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->otg_enable_hsic ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->battery_charger_support ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->lpm_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg3->total_fifo_size ); + + // HW configure 4 + TU_LOG(DWC2_DEBUG, "\r\n"); + TU_LOG_HEX(DWC2_DEBUG, dwc2->ghwcfg4); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_period_in_ep ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->power_optimized ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ahb_freq_min ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->hibernation ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->service_interval_mode ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->ipg_isoc_en ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->acg_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->utmi_phy_data_width ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dev_ctrl_ep_num ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->iddg_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->vbus_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->a_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->b_valid_filter_enabled ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dedicated_fifos ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->num_dev_in_eps ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_desc_enable ); + TU_LOG_INT(DWC2_DEBUG, hw_cfg4->dma_dynamic ); +} +#endif + +static void reset_core(dwc2_regs_t * dwc2) +{ + // reset core + dwc2->grstctl |= GRSTCTL_CSRST; + + // wait for reset bit is cleared + // TODO version 4.20a should wait for RESET DONE mask + while (dwc2->grstctl & GRSTCTL_CSRST) { } + + // wait for AHB master IDLE + while ( !(dwc2->grstctl & GRSTCTL_AHBIDL) ) { } + + // wait for device mode ? +} + +static bool phy_hs_supported(dwc2_regs_t * dwc2) +{ + // note: esp32 incorrect report its hs_phy_type as utmi +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + return false; +#else + return TUD_OPT_HIGH_SPEED && dwc2->ghwcfg2_bm.hs_phy_type != HS_PHY_TYPE_NONE; +#endif +} + +static void phy_fs_init(dwc2_regs_t * dwc2) +{ + TU_LOG(DWC2_DEBUG, "Fullspeed PHY init\r\n"); + + // Select FS PHY + dwc2->gusbcfg |= GUSBCFG_PHYSEL; + + // MCU specific PHY init before reset + dwc2_phy_init(dwc2, HS_PHY_TYPE_NONE); + + // Reset core after selecting PHY + reset_core(dwc2); + + // USB turnaround time is critical for certification where long cables and 5-Hubs are used. + // So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical, + // these bits can be programmed to a larger value. Default is 5 + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (5u << GUSBCFG_TRDT_Pos); + + // MCU specific PHY update post reset + dwc2_phy_update(dwc2, HS_PHY_TYPE_NONE); + + // set max speed + dwc2->dcfg = (dwc2->dcfg & ~DCFG_DSPD_Msk) | (DCFG_DSPD_FS << DCFG_DSPD_Pos); +} + +static void phy_hs_init(dwc2_regs_t * dwc2) +{ + uint32_t gusbcfg = dwc2->gusbcfg; + + // De-select FS PHY + gusbcfg &= ~GUSBCFG_PHYSEL; + + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) + { + TU_LOG(DWC2_DEBUG, "Highspeed ULPI PHY init\r\n"); + + // Select ULPI + gusbcfg |= GUSBCFG_ULPI_UTMI_SEL; + + // ULPI 8-bit interface, single data rate + gusbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); + + // default internal VBUS Indicator and Drive + gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI); + + // Disable FS/LS ULPI + gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM); + }else + { + TU_LOG(DWC2_DEBUG, "Highspeed UTMI+ PHY init\r\n"); + + // Select UTMI+ with 8-bit interface + gusbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); + + // Set 16-bit interface if supported + if (dwc2->ghwcfg4_bm.utmi_phy_data_width) gusbcfg |= GUSBCFG_PHYIF16; + } + + // Apply config + dwc2->gusbcfg = gusbcfg; + + // mcu specific phy init + dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + + // Reset core after selecting PHY + reset_core(dwc2); + + // Set turn-around, must after core reset otherwise it will be clear + // - 9 if using 8-bit PHY interface + // - 5 if using 16-bit PHY interface + gusbcfg &= ~GUSBCFG_TRDT_Msk; + gusbcfg |= (dwc2->ghwcfg4_bm.utmi_phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos; + dwc2->gusbcfg = gusbcfg; + + // MCU specific PHY update post reset + dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type); + + // Set max speed + uint32_t dcfg = dwc2->dcfg; + dcfg &= ~DCFG_DSPD_Msk; + dcfg |= DCFG_DSPD_HS << DCFG_DSPD_Pos; + + // XCVRDLY: transceiver delay between xcvr_sel and txvalid during device chirp is required + // when using with some PHYs such as USB334x (USB3341, USB3343, USB3346, USB3347) + if (dwc2->ghwcfg2_bm.hs_phy_type == HS_PHY_TYPE_ULPI) dcfg |= DCFG_XCVRDLY; + + dwc2->dcfg = dcfg; +} + +static bool check_dwc2(dwc2_regs_t * dwc2) +{ +#if CFG_TUSB_DEBUG >= DWC2_DEBUG + print_dwc2_info(dwc2); +#endif + + // For some reasons: GD32VF103 snpsid and all hwcfg register are always zero (skip it) + (void) dwc2; +#if !TU_CHECK_MCU(OPT_MCU_GD32VF103) + uint32_t const gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK; + TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID); +#endif + + return true; +} + +void dcd_init (uint8_t rhport) +{ + // Programming model begins in the last section of the chapter on the USB + // peripheral in each Reference Manual. + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // Check Synopsys ID register, failed if controller clock/power is not enabled + TU_VERIFY(check_dwc2(dwc2), ); + + dcd_disconnect(rhport); + + // max number of endpoints & total_fifo_size are: + // hw_cfg2->num_dev_ep, hw_cfg2->total_fifo_size + + if( phy_hs_supported(dwc2) ) + { + // Highspeed + phy_hs_init(dwc2); + }else + { + // core does not support highspeed or hs-phy is not present + phy_fs_init(dwc2); + } + + // Restart PHY clock + dwc2->pcgctl &= ~(PCGCTL_STOPPCLK | PCGCTL_GATEHCLK | PCGCTL_PWRCLMP | PCGCTL_RSTPDWNMODULE); + + /* Set HS/FS Timeout Calibration to 7 (max available value). + * The number of PHY clocks that the application programs in + * this field is added to the high/full speed interpacket timeout + * duration in the core to account for any additional delays + * introduced by the PHY. This can be required, because the delay + * introduced by the PHY in generating the linestate condition + * can vary from one PHY to another. + */ + dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos); + + // Force device mode + dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_FHMOD) | GUSBCFG_FDMOD; + + // Clear A override, force B Valid + dwc2->gotgctl = (dwc2->gotgctl & ~GOTGCTL_AVALOEN) | GOTGCTL_BVALOEN | GOTGCTL_BVALOVAL; + + // If USB host misbehaves during status portion of control xfer + // (non zero-length packet), send STALL back and discard. + dwc2->dcfg |= DCFG_NZLSOHSK; + + // Clear all interrupts + uint32_t int_mask = dwc2->gintsts; + dwc2->gintsts |= int_mask; + int_mask = dwc2->gotgint; + dwc2->gotgint |= int_mask; + + // Required as part of core initialization. + // TODO: How should mode mismatch be handled? It will cause + // the core to stop working/require reset. + dwc2->gintmsk = GINTMSK_OTGINT | GINTMSK_MMISM | GINTMSK_RXFLVLM | + GINTMSK_USBSUSPM | GINTMSK_USBRST | GINTMSK_ENUMDNEM | GINTMSK_WUIM; + + // Enable global interrupt + dwc2->gahbcfg |= GAHBCFG_GINT; + + // make sure we are in device mode +// TU_ASSERT(!(dwc2->gintsts & GINTSTS_CMOD), ); + +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gotgctl); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gusbcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->dcfg); +// TU_LOG_HEX(DWC2_DEBUG, dwc2->gahbcfg); + + dcd_connect(rhport); +} + +void dcd_int_enable (uint8_t rhport) +{ + dwc2_dcd_int_enable(rhport); +} + +void dcd_int_disable (uint8_t rhport) +{ + dwc2_dcd_int_disable(rhport); +} + +void dcd_set_address (uint8_t rhport, uint8_t dev_addr) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dcfg = (dwc2->dcfg & ~DCFG_DAD_Msk) | (dev_addr << DCFG_DAD_Pos); + + // Response with status after changing device address + dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0); +} + +void dcd_remote_wakeup(uint8_t rhport) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + // set remote wakeup + dwc2->dctl |= DCTL_RWUSIG; + + // enable SOF to detect bus resume + dwc2->gintsts = GINTSTS_SOF; + dwc2->gintmsk |= GINTMSK_SOFM; + + // Per specs: remote wakeup signal bit must be clear within 1-15ms + dwc2_remote_wakeup_delay(); + + dwc2->dctl &= ~DCTL_RWUSIG; +} + +void dcd_connect(uint8_t rhport) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dctl &= ~DCTL_SDIS; +} + +void dcd_disconnect(uint8_t rhport) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + dwc2->dctl |= DCTL_SDIS; +} + +// Be advised: audio, video and possibly other iso-ep classes use dcd_sof_enable() to enable/disable its corresponding ISR on purpose! +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + _sof_en = en; + + if (en) + { + dwc2->gintsts = GINTSTS_SOF; + dwc2->gintmsk |= GINTMSK_SOFM; + } + else + { + dwc2->gintmsk &= ~GINTMSK_SOFM; + } +} + +/*------------------------------------------------------------------*/ +/* DCD Endpoint port + *------------------------------------------------------------------*/ +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) +// Keep count of how many FIFOs are in use +static uint8_t _allocated_fifos = 1; //FIFO0 is always in use + +// Will either return an unused FIFO number, or 0 if all are used. +static uint8_t get_free_fifo(void) +{ + if (_allocated_fifos < 5) return _allocated_fifos++; + return 0; +} +#endif + +bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress); + + TU_ASSERT(epnum < ep_count); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->max_size = tu_edpt_packet_size(desc_edpt); + xfer->interval = desc_edpt->bInterval; + + uint16_t const fifo_size = tu_div_ceil(xfer->max_size, 4); + + if(dir == TUSB_DIR_OUT) + { + // Calculate required size of RX FIFO + uint16_t const sz = calc_grxfsiz(4*fifo_size, ep_count); + + // If size_rx needs to be extended check if possible and if so enlarge it + if (dwc2->grxfsiz < sz) + { + TU_ASSERT(sz + _allocated_fifo_words_tx <= _dwc2_controller[rhport].ep_fifo_size/4); + + // Enlarge RX FIFO + dwc2->grxfsiz = sz; + } + + dwc2->epout[epnum].doepctl |= (1 << DOEPCTL_USBAEP_Pos) | + (desc_edpt->bmAttributes.xfer << DOEPCTL_EPTYP_Pos) | + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DOEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DOEPCTL_MPSIZ_Pos); + + dwc2->daintmsk |= TU_BIT(DAINTMSK_OEPM_Pos + epnum); + } + else + { + // "USB Data FIFOs" section in reference manual + // Peripheral FIFO architecture + // + // --------------- 320 or 1024 ( 1280 or 4096 bytes ) + // | IN FIFO 0 | + // --------------- (320 or 1024) - 16 + // | IN FIFO 1 | + // --------------- (320 or 1024) - 16 - x + // | . . . . | + // --------------- (320 or 1024) - 16 - x - y - ... - z + // | IN FIFO MAX | + // --------------- + // | FREE | + // --------------- GRXFSIZ + // | OUT FIFO | + // | ( Shared ) | + // --------------- 0 + // + // In FIFO is allocated by following rules: + // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n". + + uint8_t fifo_num = epnum; +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + // Special Case for EP5, which is used by CDC but not actually called by the driver + // we can give it a fake FIFO + if (epnum == 5) { + fifo_num = epnum; + } else { + fifo_num = get_free_fifo(); + } + TU_ASSERT(fifo_num != 0); +#endif + // Check if free space is available + TU_ASSERT(_allocated_fifo_words_tx + fifo_size + dwc2->grxfsiz <= _dwc2_controller[rhport].ep_fifo_size/4); + + _allocated_fifo_words_tx += fifo_size; + + TU_LOG(DWC2_DEBUG, " Allocated %u bytes at offset %lu", fifo_size*4, _dwc2_controller[rhport].ep_fifo_size-_allocated_fifo_words_tx*4); + + // DIEPTXF starts at FIFO #1. + // Both TXFD and TXSA are in unit of 32-bit words. + dwc2->dieptxf[epnum - 1] = (fifo_size << DIEPTXF_INEPTXFD_Pos) | (_dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx); + + dwc2->epin[epnum].diepctl |= (1 << DIEPCTL_USBAEP_Pos) | + (fifo_num << DIEPCTL_TXFNUM_Pos) | + (desc_edpt->bmAttributes.xfer << DIEPCTL_EPTYP_Pos) | + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? DIEPCTL_SD0PID_SEVNFRM : 0) | + (xfer->max_size << DIEPCTL_MPSIZ_Pos); + + dwc2->daintmsk |= (1 << (DAINTMSK_IEPM_Pos + epnum)); + } + + return true; +} + +// Close all non-control endpoints, cancel all pending transfers if any. +void dcd_edpt_close_all (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // Disable non-control interrupt + dwc2->daintmsk = (1 << DAINTMSK_OEPM_Pos) | (1 << DAINTMSK_IEPM_Pos); + + for(uint8_t n = 1; n < ep_count; n++) + { + // disable OUT endpoint + dwc2->epout[n].doepctl = 0; + xfer_status[n][TUSB_DIR_OUT].max_size = 0; + + // disable IN endpoint + dwc2->epin[n].diepctl = 0; + xfer_status[n][TUSB_DIR_IN].max_size = 0; + } + + // reset allocated fifo IN + _allocated_fifo_words_tx = 16; +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + _allocated_fifos = 1; +#endif +} + +bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = buffer; + xfer->ff = NULL; + xfer->total_len = total_bytes; + + // EP0 can only handle one packet + if(epnum == 0) + { + ep0_pending[dir] = total_bytes; + + // Schedule the first transaction for EP0 transfer + edpt_schedule_packets(rhport, epnum, dir, 1, ep0_pending[dir]); + } + else + { + uint16_t num_packets = (total_bytes / xfer->max_size); + uint16_t const short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if ( (short_packet_size > 0) || (total_bytes == 0) ) num_packets++; + + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); + } + + return true; +} + +// The number of bytes has to be given explicitly to allow more flexible control of how many +// bytes should be written and second to keep the return value free to give back a boolean +// success message. If total_bytes is too big, the FIFO will copy only what is available +// into the USB buffer! +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 + TU_ASSERT(ff->item_size == 1); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); + xfer->buffer = NULL; + xfer->ff = ff; + xfer->total_len = total_bytes; + + uint16_t num_packets = (total_bytes / xfer->max_size); + uint16_t const short_packet_size = total_bytes % xfer->max_size; + + // Zero-size packet is special case. + if ( short_packet_size > 0 || (total_bytes == 0) ) num_packets++; + + // Schedule packets to be sent within interrupt + edpt_schedule_packets(rhport, epnum, dir, num_packets, total_bytes); + + return true; +} + +static void dcd_edpt_disable (uint8_t rhport, uint8_t ep_addr, bool stall) +{ + (void) rhport; + + dwc2_regs_t *dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + if ( dir == TUSB_DIR_IN ) + { + dwc2_epin_t* epin = dwc2->epin; + + // Only disable currently enabled non-control endpoint + if ( (epnum == 0) || !(epin[epnum].diepctl & DIEPCTL_EPENA) ) + { + epin[epnum].diepctl |= DIEPCTL_SNAK | (stall ? DIEPCTL_STALL : 0); + } + else + { + // Stop transmitting packets and NAK IN xfers. + epin[epnum].diepctl |= DIEPCTL_SNAK; + while ( (epin[epnum].diepint & DIEPINT_INEPNE) == 0 ) {} + + // Disable the endpoint. + epin[epnum].diepctl |= DIEPCTL_EPDIS | (stall ? DIEPCTL_STALL : 0); + while ( (epin[epnum].diepint & DIEPINT_EPDISD_Msk) == 0 ) {} + + epin[epnum].diepint = DIEPINT_EPDISD; + } + + // Flush the FIFO, and wait until we have confirmed it cleared. + dwc2->grstctl = ((epnum << GRSTCTL_TXFNUM_Pos) | GRSTCTL_TXFFLSH); + while ( (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) != 0 ) {} + } + else + { + dwc2_epout_t* epout = dwc2->epout; + + // Only disable currently enabled non-control endpoint + if ( (epnum == 0) || !(epout[epnum].doepctl & DOEPCTL_EPENA) ) + { + epout[epnum].doepctl |= stall ? DOEPCTL_STALL : 0; + } + else + { + // Asserting GONAK is required to STALL an OUT endpoint. + // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt + // anyway, and it can't be cleared by user code. If this while loop never + // finishes, we have bigger problems than just the stack. + dwc2->dctl |= DCTL_SGONAK; + while ( (dwc2->gintsts & GINTSTS_BOUTNAKEFF_Msk) == 0 ) {} + + // Ditto here- disable the endpoint. + epout[epnum].doepctl |= DOEPCTL_EPDIS | (stall ? DOEPCTL_STALL : 0); + while ( (epout[epnum].doepint & DOEPINT_EPDISD_Msk) == 0 ) {} + + epout[epnum].doepint = DOEPINT_EPDISD; + + // Allow other OUT endpoints to keep receiving. + dwc2->dctl |= DCTL_CGONAK; + } + } +} + +/** + * Close an endpoint. + */ +void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + dcd_edpt_disable(rhport, ep_addr, false); + + // Update max_size + xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation + + if (dir == TUSB_DIR_IN) + { + uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos; + uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos; + + // For now only the last opened endpoint can be closed without fuss. + TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size/4 - _allocated_fifo_words_tx,); + _allocated_fifo_words_tx -= fifo_size; + } + else + { + _out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty + } +} + +void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) +{ + dcd_edpt_disable(rhport, ep_addr, true); +} + +void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + // Clear stall and reset data toggle + if ( dir == TUSB_DIR_IN ) + { + dwc2->epin[epnum].diepctl &= ~DIEPCTL_STALL; + dwc2->epin[epnum].diepctl |= DIEPCTL_SD0PID_SEVNFRM; + } + else + { + dwc2->epout[epnum].doepctl &= ~DOEPCTL_STALL; + dwc2->epout[epnum].doepctl |= DOEPCTL_SD0PID_SEVNFRM; + } +} + +/*------------------------------------------------------------------*/ + +// Read a single data packet from receive FIFO +static void read_fifo_packet(uint8_t rhport, uint8_t * dst, uint16_t len) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile const uint32_t * rx_fifo = dwc2->fifo[0]; + + // Reading full available 32 bit words from fifo + uint16_t full_words = len >> 2; + while(full_words--) + { + tu_unaligned_write32(dst, *rx_fifo); + dst += 4; + } + + // Read the remaining 1-3 bytes from fifo + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem != 0 ) + { + uint32_t const tmp = *rx_fifo; + dst[0] = tu_u32_byte0(tmp); + if ( bytes_rem > 1 ) dst[1] = tu_u32_byte1(tmp); + if ( bytes_rem > 2 ) dst[2] = tu_u32_byte2(tmp); + } +} + +// Write a single data packet to EPIN FIFO +static void write_fifo_packet(uint8_t rhport, uint8_t fifo_num, uint8_t const * src, uint16_t len) +{ + (void) rhport; + + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile uint32_t * tx_fifo = dwc2->fifo[fifo_num]; + + // Pushing full available 32 bit words to fifo + uint16_t full_words = len >> 2; + while(full_words--) + { + *tx_fifo = tu_unaligned_read32(src); + src += 4; + } + + // Write the remaining 1-3 bytes into fifo + uint8_t const bytes_rem = len & 0x03; + if ( bytes_rem ) + { + uint32_t tmp_word = src[0]; + if ( bytes_rem > 1 ) tmp_word |= (src[1] << 8); + if ( bytes_rem > 2 ) tmp_word |= (src[2] << 16); + + *tx_fifo = tmp_word; + } +} + +static void handle_rxflvl_irq(uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + volatile uint32_t const * rx_fifo = dwc2->fifo[0]; + + // Pop control word off FIFO + uint32_t const ctl_word = dwc2->grxstsp; + uint8_t const pktsts = (ctl_word & GRXSTSP_PKTSTS_Msk ) >> GRXSTSP_PKTSTS_Pos; + uint8_t const epnum = (ctl_word & GRXSTSP_EPNUM_Msk ) >> GRXSTSP_EPNUM_Pos; + uint16_t const bcnt = (ctl_word & GRXSTSP_BCNT_Msk ) >> GRXSTSP_BCNT_Pos; + + dwc2_epout_t* epout = &dwc2->epout[epnum]; + +//#if CFG_TUSB_DEBUG >= DWC2_DEBUG +// const char * pktsts_str[] = +// { +// "ASSERT", "Global NAK (ISR)", "Out Data Received", "Out Transfer Complete (ISR)", +// "Setup Complete (ISR)", "ASSERT", "Setup Data Received" +// }; +// TU_LOG_LOCATION(); +// TU_LOG(DWC2_DEBUG, " EP %02X, Byte Count %u, %s\r\n", epnum, bcnt, pktsts_str[pktsts]); +// TU_LOG(DWC2_DEBUG, " daint = %08lX, doepint = %04X\r\n", (unsigned long) dwc2->daint, (unsigned int) epout->doepint); +//#endif + + switch ( pktsts ) + { + // Global OUT NAK: do nothing + case GRXSTS_PKTSTS_GLOBALOUTNAK: break; + + case GRXSTS_PKTSTS_SETUPRX: + // Setup packet received + + // We can receive up to three setup packets in succession, but + // only the last one is valid. + _setup_packet[0] = (*rx_fifo); + _setup_packet[1] = (*rx_fifo); + break; + + case GRXSTS_PKTSTS_SETUPDONE: + // Setup packet done (Interrupt) + epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); + break; + + case GRXSTS_PKTSTS_OUTRX: + { + // Out packet received + xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT); + + // Read packet off RxFIFO + if ( xfer->ff ) + { + // Ring buffer + tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void*) (uintptr_t) rx_fifo, bcnt); + } + else + { + // Linear buffer + read_fifo_packet(rhport, xfer->buffer, bcnt); + + // Increment pointer to xfer data + xfer->buffer += bcnt; + } + + // Truncate transfer length in case of short packet + if ( bcnt < xfer->max_size ) + { + xfer->total_len -= (epout->doeptsiz & DOEPTSIZ_XFRSIZ_Msk) >> DOEPTSIZ_XFRSIZ_Pos; + if ( epnum == 0 ) + { + xfer->total_len -= ep0_pending[TUSB_DIR_OUT]; + ep0_pending[TUSB_DIR_OUT] = 0; + } + } + } + break; + + // Out packet done (Interrupt) + case GRXSTS_PKTSTS_OUTDONE: + // Occurred on STM32L47 with dwc2 version 3.10a but not found on other version like 2.80a or 3.30a + // May (or not) be 3.10a specific feature/bug or depending on MCU configuration + // XFRC complete is additionally generated when + // - setup packet is received + // - complete the data stage of control write is complete + if ((epnum == 0) && (bcnt == 0) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) + { + uint32_t doepint = epout->doepint; + + if (doepint & (DOEPINT_STPKTRX | DOEPINT_OTEPSPR)) + { + // skip this "no-data" transfer complete event + // Note: STPKTRX will be clear later by setup received handler + uint32_t clear_flags = DOEPINT_XFRC; + + if (doepint & DOEPINT_OTEPSPR) clear_flags |= DOEPINT_OTEPSPR; + + epout->doepint = clear_flags; + + // TU_LOG(DWC2_DEBUG, " FIX extra transfer complete on setup/data compete\r\n"); + } + } + break; + + default: // Invalid + TU_BREAKPOINT(); + break; + } +} + +static void handle_epout_irq (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + + // DAINT for a given EP clears when DOEPINTx is cleared. + // OEPINT will be cleared when DAINT's out bits are cleared. + for ( uint8_t n = 0; n < ep_count; n++ ) + { + if ( dwc2->daint & TU_BIT(DAINT_OEPINT_Pos + n) ) + { + dwc2_epout_t* epout = &dwc2->epout[n]; + + uint32_t const doepint = epout->doepint; + + // SETUP packet Setup Phase done. + if ( doepint & DOEPINT_STUP ) + { + uint32_t clear_flag = DOEPINT_STUP; + + // STPKTRX is only available for version from 3_00a + if ((doepint & DOEPINT_STPKTRX) && (dwc2->gsnpsid >= DWC2_CORE_REV_3_00a)) + { + clear_flag |= DOEPINT_STPKTRX; + } + + epout->doepint = clear_flag; + dcd_event_setup_received(rhport, (uint8_t*) _setup_packet, true); + } + + // OUT XFER complete + if ( epout->doepint & DOEPINT_XFRC ) + { + epout->doepint = DOEPINT_XFRC; + + xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT); + + // EP0 can only handle one packet + if ( (n == 0) && ep0_pending[TUSB_DIR_OUT] ) + { + // Schedule another packet to be received. + edpt_schedule_packets(rhport, n, TUSB_DIR_OUT, 1, ep0_pending[TUSB_DIR_OUT]); + } + else + { + dcd_event_xfer_complete(rhport, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + } + } +} + +static void handle_epin_irq (uint8_t rhport) +{ + dwc2_regs_t * dwc2 = DWC2_REG(rhport); + uint8_t const ep_count = _dwc2_controller[rhport].ep_count; + dwc2_epin_t* epin = dwc2->epin; + + // DAINT for a given EP clears when DIEPINTx is cleared. + // IEPINT will be cleared when DAINT's out bits are cleared. + for ( uint8_t n = 0; n < ep_count; n++ ) + { + if ( dwc2->daint & TU_BIT(DAINT_IEPINT_Pos + n) ) + { + // IN XFER complete (entire xfer). + xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_IN); + + if ( epin[n].diepint & DIEPINT_XFRC ) + { + epin[n].diepint = DIEPINT_XFRC; + + // EP0 can only handle one packet + if ( (n == 0) && ep0_pending[TUSB_DIR_IN] ) + { + // Schedule another packet to be transmitted. + edpt_schedule_packets(rhport, n, TUSB_DIR_IN, 1, ep0_pending[TUSB_DIR_IN]); + } + else + { + dcd_event_xfer_complete(rhport, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + } + } + + // XFER FIFO empty + if ( (epin[n].diepint & DIEPINT_TXFE) && (dwc2->diepempmsk & (1 << n)) ) + { + // diepint's TXFE bit is read-only, software cannot clear it. + // It will only be cleared by hardware when written bytes is more than + // - 64 bytes or + // - Half of TX FIFO size (configured by DIEPTXF) + + uint16_t remaining_packets = (epin[n].dieptsiz & DIEPTSIZ_PKTCNT_Msk) >> DIEPTSIZ_PKTCNT_Pos; + + // Process every single packet (only whole packets can be written to fifo) + for ( uint16_t i = 0; i < remaining_packets; i++ ) + { + uint16_t const remaining_bytes = (epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos; + + // Packet can not be larger than ep max size + uint16_t const packet_size = tu_min16(remaining_bytes, xfer->max_size); + + // It's only possible to write full packets into FIFO. Therefore DTXFSTS register of current + // EP has to be checked if the buffer can take another WHOLE packet + if ( packet_size > ((epin[n].dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2) ) break; + + // Push packet to Tx-FIFO + if ( xfer->ff ) + { + volatile uint32_t *tx_fifo = dwc2->fifo[n]; + tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*) (uintptr_t) tx_fifo, packet_size); + } + else + { + write_fifo_packet(rhport, n, xfer->buffer, packet_size); + + // Increment pointer to xfer data + xfer->buffer += packet_size; + } + } + + // Turn off TXFE if all bytes are written. + if ( ((epin[n].dieptsiz & DIEPTSIZ_XFRSIZ_Msk) >> DIEPTSIZ_XFRSIZ_Pos) == 0 ) + { + dwc2->diepempmsk &= ~(1 << n); + } + } + } + } +} + +void dcd_int_handler(uint8_t rhport) +{ + dwc2_regs_t *dwc2 = DWC2_REG(rhport); + + uint32_t const int_mask = dwc2->gintmsk; + uint32_t const int_status = dwc2->gintsts & int_mask; + + if(int_status & GINTSTS_USBRST) + { + // USBRST is start of reset. + dwc2->gintsts = GINTSTS_USBRST; +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + _allocated_fifos = 1; +#endif + bus_reset(rhport); + } + + if(int_status & GINTSTS_ENUMDNE) + { + // ENUMDNE is the end of reset where speed of the link is detected + + dwc2->gintsts = GINTSTS_ENUMDNE; + + tusb_speed_t speed; + switch ((dwc2->dsts & DSTS_ENUMSPD_Msk) >> DSTS_ENUMSPD_Pos) + { + case DSTS_ENUMSPD_HS: + speed = TUSB_SPEED_HIGH; + break; + + case DSTS_ENUMSPD_LS: + speed = TUSB_SPEED_LOW; + break; + + case DSTS_ENUMSPD_FS_HSPHY: + case DSTS_ENUMSPD_FS: + default: + speed = TUSB_SPEED_FULL; + break; + } + + dcd_event_bus_reset(rhport, speed, true); + } + + if(int_status & GINTSTS_USBSUSP) + { + dwc2->gintsts = GINTSTS_USBSUSP; + //dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + _allocated_fifos = 1; +#endif + } + + if(int_status & GINTSTS_WKUINT) + { + dwc2->gintsts = GINTSTS_WKUINT; + dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); + } + + // TODO check GINTSTS_DISCINT for disconnect detection + // if(int_status & GINTSTS_DISCINT) + + if(int_status & GINTSTS_OTGINT) + { + // OTG INT bit is read-only + uint32_t const otg_int = dwc2->gotgint; + + if (otg_int & GOTGINT_SEDET) + { + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); +#if TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3) + _allocated_fifos = 1; +#endif + } + + dwc2->gotgint = otg_int; + } + + if(int_status & GINTSTS_SOF) + { + dwc2->gotgint = GINTSTS_SOF; + + if (_sof_en) + { + uint32_t frame = (dwc2->dsts & (DSTS_FNSOF)) >> 8; + dcd_event_sof(rhport, frame, true); + } + else + { + // Disable SOF interrupt if SOF was not explicitly enabled. SOF was used for remote wakeup detection + dwc2->gintmsk &= ~GINTMSK_SOFM; + } + + dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); + } + + // RxFIFO non-empty interrupt handling. + if(int_status & GINTSTS_RXFLVL) + { + // RXFLVL bit is read-only + + // Mask out RXFLVL while reading data from FIFO + dwc2->gintmsk &= ~GINTMSK_RXFLVLM; + + // Loop until all available packets were handled + do + { + handle_rxflvl_irq(rhport); + } while(dwc2->gotgint & GINTSTS_RXFLVL); + + // Manage RX FIFO size + if (_out_ep_closed) + { + update_grxfsiz(rhport); + + // Disable flag + _out_ep_closed = false; + } + + dwc2->gintmsk |= GINTMSK_RXFLVLM; + } + + // OUT endpoint interrupt handling. + if(int_status & GINTSTS_OEPINT) + { + // OEPINT is read-only, clear using DOEPINTn + handle_epout_irq(rhport); + } + + // IN endpoint interrupt handling. + if(int_status & GINTSTS_IEPINT) + { + // IEPINT bit read-only, clear using DIEPINTn + handle_epin_irq(rhport); + } + + // // Check for Incomplete isochronous IN transfer + // if(int_status & GINTSTS_IISOIXFR) { + // printf(" IISOIXFR!\r\n"); + //// TU_LOG(DWC2_DEBUG, " IISOIXFR!\r\n"); + // } +} + +#endif diff --git a/components/arduino_tinyusb/src/dcd_esp32sx.c b/components/arduino_tinyusb/src/dcd_esp32sx.c index 048b44e61..cfccf95ae 100755 --- a/components/arduino_tinyusb/src/dcd_esp32sx.c +++ b/components/arduino_tinyusb/src/dcd_esp32sx.c @@ -28,17 +28,16 @@ #include "tusb_option.h" -#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && TUSB_OPT_DEVICE_ENABLED) +#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED) // Espressif -#include "driver/periph_ctrl.h" #include "freertos/xtensa_api.h" #include "esp_intr_alloc.h" #include "esp_log.h" -#include "driver/gpio.h" #include "soc/dport_reg.h" #include "soc/gpio_sig_map.h" #include "soc/usb_periph.h" +#include "soc/periph_defs.h" // for interrupt source #include "device/dcd.h" @@ -60,6 +59,7 @@ typedef struct { uint16_t queued_len; uint16_t max_size; bool short_packet; + uint8_t interval; } xfer_ctl_t; static const char *TAG = "TUSB:DCD"; @@ -284,6 +284,14 @@ void dcd_disconnect(uint8_t rhport) USB0.dctl |= USB_SFTDISCON_M; } +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; + + // TODO implement later +} + /*------------------------------------------------------------------*/ /* DCD Endpoint port *------------------------------------------------------------------*/ @@ -303,6 +311,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir); xfer->max_size = tu_edpt_packet_size(desc_edpt); + xfer->interval = desc_edpt->bInterval; if (dir == TUSB_DIR_OUT) { out_ep[epnum].doepctl &= ~(USB_D_EPTYPE0_M | USB_D_MPS0_M); @@ -423,6 +432,13 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes; USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK + // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame + if ((USB0.in_ep_reg[epnum].diepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S)); + USB0.in_ep_reg[epnum].diepctl |= (odd_frame_now ? USB_DI_SETD0PID1 : USB_DI_SETD1PID1); + } + // Enable fifo empty interrupt only if there are something to put in the fifo. if(total_bytes != 0) { USB0.dtknqr4_fifoemptymsk |= (1 << epnum); @@ -431,6 +447,13 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to // Each complete packet for OUT xfers triggers XFRC. USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S); USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M; + + // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame + if ((USB0.out_ep_reg[epnum].doepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) { + // Take odd/even bit from frame counter. + uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S)); + USB0.out_ep_reg[epnum].doepctl |= (odd_frame_now ? USB_DO_SETD0PID1 : USB_DO_SETD1PID1); + } } return true; } @@ -459,7 +482,8 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) } else { // Stop transmitting packets and NAK IN xfers. in_ep[epnum].diepctl |= USB_DI_SNAK1_M; - while ((in_ep[epnum].diepint & USB_DI_SNAK1_M) == 0) ; + // while ((in_ep[epnum].diepint & USB_DI_SNAK1_M) == 0) ; + while ((in_ep[epnum].diepint & USB_D_INEPNAKEFF1_M) == 0) ; // Disable the endpoint. Note that both SNAK and STALL are set here. in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M | USB_D_EPDIS1_M); @@ -469,9 +493,16 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) // Flush the FIFO, and wait until we have confirmed it cleared. uint8_t const fifo_num = ((in_ep[epnum].diepctl >> USB_D_TXFNUM1_S) & USB_D_TXFNUM1_V); - USB0.grstctl |= (fifo_num << USB_TXFNUM_S); - USB0.grstctl |= USB_TXFFLSH_M; + // USB0.grstctl |= (fifo_num << USB_TXFNUM_S); + // USB0.grstctl |= USB_TXFFLSH_M; + // while ((USB0.grstctl & USB_TXFFLSH_M) != 0) ; + uint32_t rstctl_last = USB0.grstctl; + uint32_t rstctl = USB_TXFFLSH_M; + rstctl |= (fifo_num << USB_TXFNUM_S); + USB0.grstctl = rstctl; while ((USB0.grstctl & USB_TXFFLSH_M) != 0) ; + USB0.grstctl = rstctl_last; + // TODO: Clear grstctl::fifo_num after fifo flsh } else { // Only disable currently enabled non-control endpoint if ((epnum == 0) || !(out_ep[epnum].doepctl & USB_EPENA0_M)) { diff --git a/configs/builds.json b/configs/builds.json index c32e465e4..ef0943054 100644 --- a/configs/builds.json +++ b/configs/builds.json @@ -4,7 +4,13 @@ "file":"libspi_flash.a", "src":"build/esp-idf/spi_flash/libspi_flash.a", "out":"lib/libspi_flash.a", - "targets":["esp32","esp32c3","esp32s2","esp32s3"] + "targets":["esp32","esp32c3","esp32s2","esp32s3","esp32c6","esp32h2"] + }, + { + "file":"libesp_psram.a", + "src":"build/esp-idf/esp_psram/libesp_psram.a", + "out":"lib/libesp_psram.a", + "targets":["esp32s3"] }, { "file":"libesp_system.a", @@ -39,41 +45,31 @@ ], "targets":[ { - "target": "esp32s3", + "target": "esp32h2", "features":[], - "idf_libs":["qio","80m","qio_ram"], + "idf_libs":["qio","64m"], "bootloaders":[ - ["qio","120m","qio_ram"], - ["qio","80m","qio_ram"], - ["dio","80m","qio_ram"], - ["opi","80m","opi_ram"] + ["qio","64m"], + ["dio","64m"], + ["qio","16m"], + ["dio","16m"] ], "mem_variants":[ - ["qio","80m","opi_ram"], - ["dio","80m","qio_ram"], - ["dio","80m","opi_ram"], - ["opi","80m","opi_ram"], - ["opi","80m","qio_ram"] + ["dio","64m"] ] }, { - "target": "esp32s2", - "features":["qio_ram"], + "target": "esp32c6", + "features":[], "idf_libs":["qio","80m"], "bootloaders":[ ["qio","80m"], - ["qout","80m"], ["dio","80m"], - ["dout","80m"], ["qio","40m"], - ["qout","40m"], - ["dio","40m"], - ["dout","40m"] + ["dio","40m"] ], "mem_variants":[ - ["qout","80m"], - ["dio","80m"], - ["dout","80m"] + ["dio","80m"] ] }, { @@ -82,18 +78,12 @@ "idf_libs":["qio","80m"], "bootloaders":[ ["qio","80m"], - ["qout","80m"], ["dio","80m"], - ["dout","80m"], ["qio","40m"], - ["qout","40m"], - ["dio","40m"], - ["dout","40m"] + ["dio","40m"] ], "mem_variants":[ - ["qout","80m"], - ["dio","80m"], - ["dout","80m"] + ["dio","80m"] ] }, { @@ -102,18 +92,44 @@ "idf_libs":["qio","80m"], "bootloaders":[ ["qio","80m"], - ["qout","80m"], ["dio","80m"], - ["dout","80m"], ["qio","40m"], - ["qout","40m"], - ["dio","40m"], - ["dout","40m"] + ["dio","40m"] ], "mem_variants":[ - ["qout","80m"], + ["dio","80m"] + ] + }, + { + "target": "esp32s2", + "features":["qio_ram"], + "idf_libs":["qio","80m"], + "bootloaders":[ + ["qio","80m"], ["dio","80m"], - ["dout","80m"] + ["qio","40m"], + ["dio","40m"] + ], + "mem_variants":[ + ["dio","80m"] + ] + }, + { + "target": "esp32s3", + "features":["esp_sr"], + "idf_libs":["qio","80m","qio_ram"], + "bootloaders":[ + ["qio","120m","qio_ram"], + ["qio","80m","qio_ram"], + ["dio","80m","qio_ram"], + ["opi","80m","opi_ram"] + ], + "mem_variants":[ + ["qio","80m","opi_ram"], + ["dio","80m","qio_ram"], + ["dio","80m","opi_ram"], + ["opi","80m","opi_ram"], + ["opi","80m","qio_ram"] ] } ] diff --git a/configs/defconfig.16m b/configs/defconfig.16m new file mode 100644 index 000000000..b7916fbce --- /dev/null +++ b/configs/defconfig.16m @@ -0,0 +1 @@ +CONFIG_ESPTOOLPY_FLASHFREQ_16M=y \ No newline at end of file diff --git a/configs/defconfig.64m b/configs/defconfig.64m new file mode 100644 index 000000000..c33173f13 --- /dev/null +++ b/configs/defconfig.64m @@ -0,0 +1 @@ +CONFIG_ESPTOOLPY_FLASHFREQ_64M=y \ No newline at end of file diff --git a/configs/defconfig.common b/configs/defconfig.common index cbcfd8d2c..68ba0ddb0 100644 --- a/configs/defconfig.common +++ b/configs/defconfig.common @@ -21,15 +21,16 @@ CONFIG_ESP_TASK_WDT_PANIC=y CONFIG_ESP_TIMER_TASK_STACK_SIZE=4096 CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_ESP_WIFI_FTM_ENABLE=y -CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8 -CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=8 -CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=16 -CONFIG_ESP32_WIFI_CSI_ENABLED=y -CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y -# CONFIG_ESP32_WIFI_IRAM_OPT is not set -# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=8 +CONFIG_ESP_WIFI_STATIC_TX_BUFFER_NUM=8 +CONFIG_ESP_WIFI_CACHE_TX_BUFFER_NUM=16 +CONFIG_ESP_WIFI_CSI_ENABLED=y +CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y +# CONFIG_ESP_WIFI_IRAM_OPT is not set +# CONFIG_ESP_WIFI_RX_IRAM_OPT is not set CONFIG_ETH_SPI_ETHERNET_DM9051=y CONFIG_ETH_SPI_ETHERNET_W5500=y +CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL=y CONFIG_FATFS_CODEPAGE_850=y CONFIG_FATFS_LFN_STACK=y # CONFIG_FATFS_API_ENCODING_ANSI_OEM is not set @@ -37,6 +38,7 @@ CONFIG_FATFS_API_ENCODING_UTF_8=y # CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT is not set CONFIG_FMB_TIMER_PORT_ENABLED=y CONFIG_FREERTOS_HZ=1000 +CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y # CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION is not set CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024 CONFIG_HEAP_POISONING_LIGHT=y @@ -75,7 +77,7 @@ CONFIG_LWIP_IPV6_AUTOCONFIG=y CONFIG_ESP_RMAKER_SKIP_VERSION_CHECK=y CONFIG_ESP_RMAKER_USER_ID_CHECK=y CONFIG_ESP_INSIGHTS_ENABLED=y -CONFIG_ESP_INSIGHTS_COREDUMP_ENABLE=y +CONFIG_ESP_INSIGHTS_COREDUMP_ENABLE=n CONFIG_ESP_INSIGHTS_TRANSPORT_HTTPS=y CONFIG_DIAG_LOG_DROP_WIFI_LOGS=y CONFIG_DIAG_ENABLE_METRICS=y @@ -84,7 +86,7 @@ CONFIG_DIAG_ENABLE_WIFI_METRICS=y CONFIG_DIAG_ENABLE_VARIABLES=y CONFIG_DIAG_ENABLE_NETWORK_VARIABLES=y CONFIG_ESP_COREDUMP_ENABLE=y -CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y +CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=n CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y CONFIG_ESP_COREDUMP_MAX_TASKS_NUM=64 diff --git a/configs/defconfig.esp32 b/configs/defconfig.esp32 index bd38b4829..65bc3f0c3 100644 --- a/configs/defconfig.esp32 +++ b/configs/defconfig.esp32 @@ -8,10 +8,9 @@ CONFIG_BT_SPP_ENABLED=y CONFIG_BT_HFP_ENABLE=y CONFIG_BT_STACK_NO_LOG=y CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y -CONFIG_ESP32_SPIRAM_SUPPORT=y +CONFIG_SPIRAM=y CONFIG_SPIRAM_OCCUPY_HSPI_HOST=y -CONFIG_ESP32_ULP_COPROC_ENABLED=y -CONFIG_ESP32_XTAL_FREQ_AUTO=y +CONFIG_ULP_COPROC_ENABLED=y # CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 is not set CONFIG_FREERTOS_FPU_IN_ISR=y # CONFIG_USE_WAKENET is not set diff --git a/configs/defconfig.esp32c3 b/configs/defconfig.esp32c3 index 31c42f7a0..ced594733 100644 --- a/configs/defconfig.esp32c3 +++ b/configs/defconfig.esp32c3 @@ -1,4 +1,4 @@ CONFIG_BT_BLE_BLUFI_ENABLE=y -CONFIG_ESP32C3_RTC_CLK_CAL_CYCLES=576 +CONFIG_RTC_CLK_CAL_CYCLES=576 # CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=2304 diff --git a/configs/defconfig.esp32c6 b/configs/defconfig.esp32c6 new file mode 100644 index 000000000..ced594733 --- /dev/null +++ b/configs/defconfig.esp32c6 @@ -0,0 +1,4 @@ +CONFIG_BT_BLE_BLUFI_ENABLE=y +CONFIG_RTC_CLK_CAL_CYCLES=576 +# CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=2304 diff --git a/configs/defconfig.esp32h2 b/configs/defconfig.esp32h2 new file mode 100644 index 000000000..ced594733 --- /dev/null +++ b/configs/defconfig.esp32h2 @@ -0,0 +1,4 @@ +CONFIG_BT_BLE_BLUFI_ENABLE=y +CONFIG_RTC_CLK_CAL_CYCLES=576 +# CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=2304 diff --git a/configs/defconfig.esp32s2 b/configs/defconfig.esp32s2 index 6dc619a9f..43568afcc 100644 --- a/configs/defconfig.esp32s2 +++ b/configs/defconfig.esp32s2 @@ -1,8 +1,9 @@ CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y -CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y -CONFIG_ESP32S2_SPIRAM_SUPPORT=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_SPIRAM=y CONFIG_ESP32S2_KEEP_USB_ALIVE=y # CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set # CONFIG_USE_WAKENET is not set # CONFIG_USE_MULTINET is not set -CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y \ No newline at end of file +CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n \ No newline at end of file diff --git a/configs/defconfig.esp32s3 b/configs/defconfig.esp32s3 index 981e224fd..df73126e2 100644 --- a/configs/defconfig.esp32s3 +++ b/configs/defconfig.esp32s3 @@ -1,13 +1,10 @@ CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y -CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y -CONFIG_ESP32S3_SPIRAM_SUPPORT=y -CONFIG_ESP32S3_RTC_CLK_CAL_CYCLES=576 +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_SPIRAM=y +CONFIG_RTC_CLK_CAL_CYCLES=576 CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_TWO=y # CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set # CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 is not set -CONFIG_SR_WN_MODEL_WN8_QUANT=y -CONFIG_SR_WN_WN8_HIESP=y -CONFIG_SR_MN_ENGLISH=y -CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION_QUANT8=y CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y -CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 \ No newline at end of file +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n \ No newline at end of file diff --git a/configs/defconfig.esp_sr b/configs/defconfig.esp_sr new file mode 100644 index 000000000..03b7c462e --- /dev/null +++ b/configs/defconfig.esp_sr @@ -0,0 +1,37 @@ +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_SR_WN_WN9_HIESP=y +CONFIG_SR_MN_CN_NONE=y +CONFIG_SR_MN_EN_MULTINET5_SINGLE_RECOGNITION_QUANT8=y +CONFIG_EN_SPEECH_COMMAND_ID0="" +CONFIG_EN_SPEECH_COMMAND_ID1="" +CONFIG_EN_SPEECH_COMMAND_ID2="" +CONFIG_EN_SPEECH_COMMAND_ID3="" +CONFIG_EN_SPEECH_COMMAND_ID4="" +CONFIG_EN_SPEECH_COMMAND_ID5="" +CONFIG_EN_SPEECH_COMMAND_ID6="" +CONFIG_EN_SPEECH_COMMAND_ID7="" +CONFIG_EN_SPEECH_COMMAND_ID8="" +CONFIG_EN_SPEECH_COMMAND_ID9="" +CONFIG_EN_SPEECH_COMMAND_ID10="" +CONFIG_EN_SPEECH_COMMAND_ID11="" +CONFIG_EN_SPEECH_COMMAND_ID12="" +CONFIG_EN_SPEECH_COMMAND_ID13="" +CONFIG_EN_SPEECH_COMMAND_ID14="" +CONFIG_EN_SPEECH_COMMAND_ID15="" +CONFIG_EN_SPEECH_COMMAND_ID16="" +CONFIG_EN_SPEECH_COMMAND_ID17="" +CONFIG_EN_SPEECH_COMMAND_ID18="" +CONFIG_EN_SPEECH_COMMAND_ID19="" +CONFIG_EN_SPEECH_COMMAND_ID20="" +CONFIG_EN_SPEECH_COMMAND_ID21="" +CONFIG_EN_SPEECH_COMMAND_ID22="" +CONFIG_EN_SPEECH_COMMAND_ID23="" +CONFIG_EN_SPEECH_COMMAND_ID24="" +CONFIG_EN_SPEECH_COMMAND_ID25="" +CONFIG_EN_SPEECH_COMMAND_ID26="" +CONFIG_EN_SPEECH_COMMAND_ID27="" +CONFIG_EN_SPEECH_COMMAND_ID28="" +CONFIG_EN_SPEECH_COMMAND_ID29="" +CONFIG_EN_SPEECH_COMMAND_ID30="" +CONFIG_EN_SPEECH_COMMAND_ID31="" diff --git a/configs/pio_end.txt b/configs/pio_end.txt new file mode 100644 index 000000000..e7544f1dd --- /dev/null +++ b/configs/pio_end.txt @@ -0,0 +1,10 @@ + "ARDUINO_ARCH_ESP32", + "ESP32", + ("F_CPU", "$BOARD_F_CPU"), + ("ARDUINO", 10812), + ("ARDUINO_VARIANT", '\\"%s\\"' % board_config.get("build.variant").replace('"', "")), + ("ARDUINO_BOARD", '\\"%s\\"' % board_config.get("name").replace('"', "")), + "ARDUINO_PARTITION_%s" % basename(board_config.get( + "build.partitions", "default.csv")).replace(".csv", "").replace("-", "_") + ] +) diff --git a/configs/pio_start.txt b/configs/pio_start.txt new file mode 100644 index 000000000..9a38020fb --- /dev/null +++ b/configs/pio_start.txt @@ -0,0 +1,40 @@ +# Copyright 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Arduino + +Arduino Wiring-based Framework allows writing cross-platform software to +control devices attached to a wide range of Arduino boards to create all +kinds of creative coding, interactive objects, spaces or physical experiences. + +http://arduino.cc/en/Reference/HomePage +""" + +# Extends: https://github.com/platformio/platform-espressif32/blob/develop/builder/main.py + +from os.path import basename, join + +from SCons.Script import DefaultEnvironment + +env = DefaultEnvironment() + +FRAMEWORK_DIR = env.PioPlatform().get_package_dir("framework-arduinoespressif32") +FRAMEWORK_SDK_DIR = env.PioPlatform().get_package_dir( + "framework-arduinoespressif32-libs" +) + +board_config = env.BoardConfig() + +env.Append( diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 8e6ddef14..a5832f914 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -10,9 +10,12 @@ config LIB_BUILDER_FLASHFREQ string default "120m" if ESPTOOLPY_FLASHFREQ_120M default "80m" if ESPTOOLPY_FLASHFREQ_80M + default "64m" if ESPTOOLPY_FLASHFREQ_64M default "40m" if ESPTOOLPY_FLASHFREQ_40M + default "32m" if ESPTOOLPY_FLASHFREQ_32M default "26m" if ESPTOOLPY_FLASHFREQ_26M default "20m" if ESPTOOLPY_FLASHFREQ_20M + default "16m" if ESPTOOLPY_FLASHFREQ_16M config LIB_BUILDER_COMPILE bool diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 000000000..2ba047577 --- /dev/null +++ b/main/idf_component.yml @@ -0,0 +1,48 @@ +dependencies: + # Required IDF version + idf: ">=5.1" + + mdns: "^1.1.0" + chmorgan/esp-libhelix-mp3: "1.0.3" + esp-dsp: "^1.3.4" + + # esp-sr: "^1.3.1" + # esp32-camera: "^2.0.4" + # esp-dl: + # git: https://github.com/espressif/esp-dl.git + # espressif/esp_rainmaker: + # path: components/esp_rainmaker + # git: https://github.com/espressif/esp-rainmaker.git + + # # Defining a dependency from the registry: + # # https://components.espressif.com/component/example/cmp + # example/cmp: "^3.3.3" # Automatically update minor releases + # + # # Other ways to define dependencies + # + # # For components maintained by Espressif only name can be used. + # # Same as `espressif/cmp` + # component: "~1.0.0" # Automatically update bugfix releases + # + # # Or in a longer form with extra parameters + # component2: + # version: ">=2.0.0" + # + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect for the `main` component. + # # All dependencies of `main` are public by default. + # public: true + # + # # For components hosted on non-default registry: + # service_url: "https://componentregistry.company.com" + # + # # For components in git repository: + # test_component: + # path: test_component + # git: ssh://git@gitlab.com/user/components.git + # + # # For test projects during component development + # # components can be used from a local directory + # # with relative or absolute path + # some_local_component: + # path: ../../projects/component diff --git a/partitions.csv b/partitions.csv new file mode 100644 index 000000000..97e41c452 --- /dev/null +++ b/partitions.csv @@ -0,0 +1,8 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x300000, +app1, app, ota_1, 0x310000, 0x300000, +spiffs, data, spiffs, 0x610000, 0x700000, +model, data, spiffs, 0xD10000, 0x2E0000, +coredump, data, coredump,0xFF0000, 0x10000, diff --git a/patches/spi_eth.diff b/patches/spi_eth.diff new file mode 100644 index 000000000..1e57dbef1 --- /dev/null +++ b/patches/spi_eth.diff @@ -0,0 +1,1139 @@ +diff --git a/components/esp_eth/include/esp_eth_mac.h b/components/esp_eth/include/esp_eth_mac.h +index dfc1af2c73b5e6a872a5c0583e0223ca86b49ae2..885d332d4363e093d84af1a196c532450386b8ce 100644 +--- a/components/esp_eth/include/esp_eth_mac.h ++++ b/components/esp_eth/include/esp_eth_mac.h +@@ -1,5 +1,5 @@ + /* +- * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD ++ * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +@@ -470,15 +470,113 @@ typedef struct { + esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config, const eth_mac_config_t *config); + #endif // CONFIG_ETH_USE_ESP32_EMAC + ++#if CONFIG_ETH_USE_SPI_ETHERNET ++/** ++ * @brief Custom SPI Driver Configuration. ++ * This structure declares configuration and callback functions to access Ethernet SPI module via ++ * user's custom SPI driver. ++ * ++ */ ++typedef struct ++{ ++ /** ++ * @brief Custom driver specific configuration data used by `init()` function. ++ * ++ * @note Type and its content is fully under user's control ++ * ++ */ ++ void *config; ++ ++ /** ++ * @brief Custom driver SPI Initialization ++ * ++ * @param[in] spi_config: Custom driver specific configuration ++ * ++ * @return ++ * - spi_ctx: when initialization is successful, a pointer to context structure holding all variables ++ * needed for subsequent SPI access operations (e.g. SPI bus identification, mutexes, etc.) ++ * - NULL: driver initialization failed ++ * ++ * @note return type and its content is fully under user's control ++ */ ++ void *(*init)(const void *spi_config); ++ ++ /** ++ * @brief Custom driver De-initialization ++ * ++ * @param[in] spi_ctx: a pointer to driver specific context structure ++ * ++ * @return ++ * - ESP_OK: driver de-initialization was successful ++ * - ESP_FAIL: driver de-initialization failed ++ * - any other failure codes are allowed to be used to provide failure isolation ++ */ ++ esp_err_t (*deinit)(void *spi_ctx); ++ ++ /** ++ * @brief Custom driver SPI read ++ * ++ * @note The read function is responsible to construct command, address and data fields ++ * of the SPI frame in format expected by particular SPI Ethernet module ++ * ++ * @param[in] spi_ctx: a pointer to driver specific context structure ++ * @param[in] cmd: command ++ * @param[in] addr: register address ++ * @param[out] data: read data ++ * @param[in] data_len: read data length in bytes ++ * ++ * @return ++ * - ESP_OK: read was successful ++ * - ESP_FAIL: read failed ++ * - any other failure codes are allowed to be used to provide failure isolation ++ */ ++ esp_err_t (*read)(void *spi_ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len); ++ ++ /** ++ * @brief Custom driver SPI write ++ * ++ * @note The write function is responsible to construct command, address and data fields ++ * of the SPI frame in format expected by particular SPI Ethernet module ++ * ++ * @param[in] spi_ctx: a pointer to driver specific context structure ++ * @param[in] cmd: command ++ * @param[in] addr: register address ++ * @param[in] data: data to write ++ * @param[in] data_len: length of data to write in bytes ++ * ++ * @return ++ * - ESP_OK: write was successful ++ * - ESP_FAIL: write failed ++ * - any other failure codes are allowed to be used to provide failure isolation ++ */ ++ esp_err_t (*write)(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); ++} eth_spi_custom_driver_t; ++ ++/** ++ * @brief Default configuration of the custom SPI driver. ++ * Internal ESP-IDF SPI Master driver is used by default. ++ * ++ */ ++#define ETH_DEFAULT_SPI \ ++ { \ ++ .config = NULL, \ ++ .init = NULL, \ ++ .deinit = NULL, \ ++ .read = NULL, \ ++ .write = NULL \ ++ } ++#endif // CONFIG_ETH_USE_SPI_ETHERNET ++ + #if CONFIG_ETH_SPI_ETHERNET_DM9051 + /** + * @brief DM9051 specific configuration + * + */ + typedef struct { +- spi_host_device_t spi_host_id; /*!< SPI peripheral */ +- spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration */ + int int_gpio_num; /*!< Interrupt GPIO number */ ++ spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */ ++ spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */ ++ eth_spi_custom_driver_t custom_spi_driver; /*!< Custom SPI driver definitions */ + } eth_dm9051_config_t; + + /** +@@ -487,9 +585,10 @@ typedef struct { + */ + #define ETH_DM9051_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ + { \ ++ .int_gpio_num = 4, \ + .spi_host_id = spi_host, \ + .spi_devcfg = spi_devcfg_p, \ +- .int_gpio_num = 4, \ ++ .custom_spi_driver = ETH_DEFAULT_SPI, \ + } + + /** +@@ -511,9 +610,10 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, + * + */ + typedef struct { +- spi_host_device_t spi_host_id; /*!< SPI peripheral */ +- spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration */ + int int_gpio_num; /*!< Interrupt GPIO number */ ++ spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined)*/ ++ spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined)*/ ++ eth_spi_custom_driver_t custom_spi_driver; /*!< Custom SPI driver definitions */ + } eth_w5500_config_t; + + /** +@@ -521,10 +621,11 @@ typedef struct { + * + */ + #define ETH_W5500_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ +- { \ +- .spi_host_id = spi_host, \ +- .spi_devcfg = spi_devcfg_p, \ +- .int_gpio_num = 4, \ ++ { \ ++ .int_gpio_num = 4, \ ++ .spi_host_id = spi_host, \ ++ .spi_devcfg = spi_devcfg_p, \ ++ .custom_spi_driver = ETH_DEFAULT_SPI, \ + } + + /** +@@ -546,9 +647,10 @@ esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, con + * + */ + typedef struct { +- spi_host_device_t spi_host_id; /*!< SPI peripheral */ +- spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration */ + int int_gpio_num; /*!< Interrupt GPIO number */ ++ spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */ ++ spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */ ++ eth_spi_custom_driver_t custom_spi_driver; /*!< Custom SPI driver definitions */ + } eth_ksz8851snl_config_t; + + /** +@@ -557,9 +659,10 @@ typedef struct { + */ + #define ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ + { \ ++ .int_gpio_num = 4, \ + .spi_host_id = spi_host, \ + .spi_devcfg = spi_devcfg_p, \ +- .int_gpio_num = 14, \ ++ .custom_spi_driver = ETH_DEFAULT_SPI, \ + } + + /** +diff --git a/components/esp_eth/src/esp_eth_mac_dm9051.c b/components/esp_eth/src/esp_eth_mac_dm9051.c +index b0d339cc93d1d6ef39b1e819102c220d431114b2..ba796121b7065ba984cfbc683283e82a6702a04a 100644 +--- a/components/esp_eth/src/esp_eth_mac_dm9051.c ++++ b/components/esp_eth/src/esp_eth_mac_dm9051.c +@@ -1,5 +1,5 @@ + /* +- * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD ++ * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +@@ -47,11 +47,23 @@ typedef struct { + uint8_t length_high; + } dm9051_rx_header_t; + ++typedef struct { ++ spi_device_handle_t hdl; ++ SemaphoreHandle_t lock; ++} spi_info_t; ++ ++typedef struct { ++ void *ctx; ++ void *(*init)(const void *spi_config); ++ esp_err_t (*deinit)(void *spi_ctx); ++ esp_err_t (*read)(void *spi_ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len); ++ esp_err_t (*write)(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); ++} spi_interface_t; ++ + typedef struct { + esp_eth_mac_t parent; + esp_eth_mediator_t *eth; +- spi_device_handle_t spi_hdl; +- SemaphoreHandle_t spi_lock; ++ spi_interface_t spi; + TaskHandle_t rx_task_hdl; + uint32_t sw_reset_timeout_ms; + int int_gpio_num; +@@ -61,89 +73,137 @@ typedef struct { + uint8_t *rx_buffer; + } emac_dm9051_t; + +-static inline bool dm9051_lock(emac_dm9051_t *emac) ++static void *dm9051_spi_init(const void *spi_config) ++{ ++ void *ret = NULL; ++ eth_dm9051_config_t *dm9051_config = (eth_dm9051_config_t *)spi_config; ++ spi_info_t *spi = calloc(1, sizeof(spi_info_t)); ++ ESP_GOTO_ON_FALSE(spi, NULL, err, TAG, "no memory for SPI context data"); ++ ++ /* SPI device init */ ++ spi_device_interface_config_t spi_devcfg; ++ spi_devcfg = *(dm9051_config->spi_devcfg); ++ if (dm9051_config->spi_devcfg->command_bits == 0 && dm9051_config->spi_devcfg->address_bits == 0) { ++ /* configure default SPI frame format */ ++ spi_devcfg.command_bits = 1; ++ spi_devcfg.address_bits = 7; ++ } else { ++ ESP_GOTO_ON_FALSE(dm9051_config->spi_devcfg->command_bits == 1 && dm9051_config->spi_devcfg->address_bits == 7, ++ NULL, err, TAG, "incorrect SPI frame format (command_bits/address_bits)"); ++ } ++ ESP_GOTO_ON_FALSE(spi_bus_add_device(dm9051_config->spi_host_id, &spi_devcfg, &spi->hdl) == ESP_OK, ++ NULL, err, TAG, "adding device to SPI host #%d failed", dm9051_config->spi_host_id + 1); ++ ++ /* create mutex */ ++ spi->lock = xSemaphoreCreateMutex(); ++ ESP_GOTO_ON_FALSE(spi->lock, NULL, err, TAG, "create lock failed"); ++ ++ ret = spi; ++ return ret; ++err: ++ if (spi) { ++ if (spi->lock) { ++ vSemaphoreDelete(spi->lock); ++ } ++ free(spi); ++ } ++ return ret; ++} ++ ++static esp_err_t dm9051_spi_deinit(void *spi_ctx) + { +- return xSemaphoreTake(emac->spi_lock, pdMS_TO_TICKS(DM9051_SPI_LOCK_TIMEOUT_MS)) == pdTRUE; ++ esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; ++ ++ spi_bus_remove_device(spi->hdl); ++ vSemaphoreDelete(spi->lock); ++ ++ free(spi); ++ return ret; + } + +-static inline bool dm9051_unlock(emac_dm9051_t *emac) ++static inline bool dm9051_spi_lock(spi_info_t *spi) + { +- return xSemaphoreGive(emac->spi_lock) == pdTRUE; ++ return xSemaphoreTake(spi->lock, pdMS_TO_TICKS(DM9051_SPI_LOCK_TIMEOUT_MS)) == pdTRUE; + } + +-/** +- * @brief write value to dm9051 internal register +- */ +-static esp_err_t dm9051_register_write(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t value) ++static inline bool dm9051_spi_unlock(spi_info_t *spi) ++{ ++ return xSemaphoreGive(spi->lock) == pdTRUE; ++} ++ ++static esp_err_t dm9051_spi_write(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *value, uint32_t len) + { + esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; ++ + spi_transaction_t trans = { +- .cmd = DM9051_SPI_WR, +- .addr = reg_addr, +- .length = 8, +- .flags = SPI_TRANS_USE_TXDATA ++ .cmd = cmd, ++ .addr = addr, ++ .length = 8 * len, ++ .tx_buffer = value + }; +- trans.tx_data[0] = value; +- if (dm9051_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { ++ if (dm9051_spi_lock(spi)) { ++ if (spi_device_polling_transmit(spi->hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } +- dm9051_unlock(emac); ++ dm9051_spi_unlock(spi); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; + } + +-/** +- * @brief read value from dm9051 internal register +- */ +-static esp_err_t dm9051_register_read(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t *value) ++static esp_err_t dm9051_spi_read(void *spi_ctx, uint32_t cmd, uint32_t addr, void *value, uint32_t len) + { + esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; ++ + spi_transaction_t trans = { +- .cmd = DM9051_SPI_RD, +- .addr = reg_addr, +- .length = 8, +- .flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA ++ .flags = len <= 4 ? SPI_TRANS_USE_RXDATA : 0, // use direct reads for registers to prevent overwrites by 4-byte boundary writes ++ .cmd = cmd, ++ .addr = addr, ++ .length = 8 * len, ++ .rx_buffer = value + }; +- if (dm9051_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { ++ if (dm9051_spi_lock(spi)) { ++ if (spi_device_polling_transmit(spi->hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; +- } else { +- *value = trans.rx_data[0]; + } +- dm9051_unlock(emac); ++ dm9051_spi_unlock(spi); + } else { + ret = ESP_ERR_TIMEOUT; + } ++ if ((trans.flags&SPI_TRANS_USE_RXDATA) && len <= 4) { ++ memcpy(value, trans.rx_data, len); // copy register values to output ++ } + return ret; + } + ++/** ++ * @brief write value to dm9051 internal register ++ */ ++static esp_err_t dm9051_register_write(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t value) ++{ ++ return emac->spi.write(emac->spi.ctx, DM9051_SPI_WR, reg_addr, &value, 1); ++} ++ ++/** ++ * @brief read value from dm9051 internal register ++ */ ++static esp_err_t dm9051_register_read(emac_dm9051_t *emac, uint8_t reg_addr, uint8_t *value) ++{ ++ return emac->spi.read(emac->spi.ctx, DM9051_SPI_RD, reg_addr, value, 1); ++} ++ + /** + * @brief write buffer to dm9051 internal memory + */ + static esp_err_t dm9051_memory_write(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len) + { +- esp_err_t ret = ESP_OK; +- spi_transaction_t trans = { +- .cmd = DM9051_SPI_WR, +- .addr = DM9051_MWCMD, +- .length = len * 8, +- .tx_buffer = buffer +- }; +- if (dm9051_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { +- ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); +- ret = ESP_FAIL; +- } +- dm9051_unlock(emac); +- } else { +- ret = ESP_ERR_TIMEOUT; +- } +- return ret; ++ return emac->spi.write(emac->spi.ctx, DM9051_SPI_WR, DM9051_MWCMD, buffer, len); + } + + /** +@@ -151,23 +211,7 @@ static esp_err_t dm9051_memory_write(emac_dm9051_t *emac, uint8_t *buffer, uint3 + */ + static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len) + { +- esp_err_t ret = ESP_OK; +- spi_transaction_t trans = { +- .cmd = DM9051_SPI_RD, +- .addr = DM9051_MRCMD, +- .length = len * 8, +- .rx_buffer = buffer +- }; +- if (dm9051_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { +- ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); +- ret = ESP_FAIL; +- } +- dm9051_unlock(emac); +- } else { +- ret = ESP_ERR_TIMEOUT; +- } +- return ret; ++ return emac->spi.read(emac->spi.ctx, DM9051_SPI_RD, DM9051_MRCMD, buffer, len); + } + + /** +@@ -175,23 +219,7 @@ static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32 + */ + static esp_err_t dm9051_memory_peek(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len) + { +- esp_err_t ret = ESP_OK; +- spi_transaction_t trans = { +- .cmd = DM9051_SPI_RD, +- .addr = DM9051_MRCMDX1, +- .length = len * 8, +- .rx_buffer = buffer +- }; +- if (dm9051_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { +- ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); +- ret = ESP_FAIL; +- } +- dm9051_unlock(emac); +- } else { +- ret = ESP_ERR_TIMEOUT; +- } +- return ret; ++ return emac->spi.read(emac->spi.ctx, DM9051_SPI_RD, DM9051_MRCMDX1, buffer, len); + } + + /** +@@ -840,8 +868,7 @@ static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac) + { + emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent); + vTaskDelete(emac->rx_task_hdl); +- spi_bus_remove_device(emac->spi_hdl); +- vSemaphoreDelete(emac->spi_lock); ++ emac->spi.deinit(emac->spi.ctx); + heap_caps_free(emac->rx_buffer); + free(emac); + return ESP_OK; +@@ -857,19 +884,6 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, + ESP_GOTO_ON_FALSE(emac, NULL, err, TAG, "calloc emac failed"); + /* dm9051 receive is driven by interrupt only for now*/ + ESP_GOTO_ON_FALSE(dm9051_config->int_gpio_num >= 0, NULL, err, TAG, "error interrupt gpio number"); +- /* SPI device init */ +- spi_device_interface_config_t spi_devcfg; +- memcpy(&spi_devcfg, dm9051_config->spi_devcfg, sizeof(spi_device_interface_config_t)); +- if (dm9051_config->spi_devcfg->command_bits == 0 && dm9051_config->spi_devcfg->address_bits == 0) { +- /* configure default SPI frame format */ +- spi_devcfg.command_bits = 1; +- spi_devcfg.address_bits = 7; +- } else { +- ESP_GOTO_ON_FALSE(dm9051_config->spi_devcfg->command_bits == 1 || dm9051_config->spi_devcfg->address_bits == 7, +- NULL, err, TAG, "incorrect SPI frame format (command_bits/address_bits)"); +- } +- ESP_GOTO_ON_FALSE(spi_bus_add_device(dm9051_config->spi_host_id, &spi_devcfg, &emac->spi_hdl) == ESP_OK, +- NULL, err, TAG, "adding device to SPI host #%d failed", dm9051_config->spi_host_id + 1); + /* bind methods and attributes */ + emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms; + emac->int_gpio_num = dm9051_config->int_gpio_num; +@@ -891,9 +905,26 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, + emac->parent.enable_flow_ctrl = emac_dm9051_enable_flow_ctrl; + emac->parent.transmit = emac_dm9051_transmit; + emac->parent.receive = emac_dm9051_receive; +- /* create mutex */ +- emac->spi_lock = xSemaphoreCreateMutex(); +- ESP_GOTO_ON_FALSE(emac->spi_lock, NULL, err, TAG, "create lock failed"); ++ ++ if (dm9051_config->custom_spi_driver.init != NULL && dm9051_config->custom_spi_driver.deinit != NULL ++ && dm9051_config->custom_spi_driver.read != NULL && dm9051_config->custom_spi_driver.write != NULL) { ++ ESP_LOGD(TAG, "Using user's custom SPI Driver"); ++ emac->spi.init = dm9051_config->custom_spi_driver.init; ++ emac->spi.deinit = dm9051_config->custom_spi_driver.deinit; ++ emac->spi.read = dm9051_config->custom_spi_driver.read; ++ emac->spi.write = dm9051_config->custom_spi_driver.write; ++ /* Custom SPI driver device init */ ++ ESP_GOTO_ON_FALSE((emac->spi.ctx = emac->spi.init(dm9051_config->custom_spi_driver.config)) != NULL, NULL, err, TAG, "SPI initialization failed"); ++ } else { ++ ESP_LOGD(TAG, "Using default SPI Driver"); ++ emac->spi.init = dm9051_spi_init; ++ emac->spi.deinit = dm9051_spi_deinit; ++ emac->spi.read = dm9051_spi_read; ++ emac->spi.write = dm9051_spi_write; ++ /* SPI device init */ ++ ESP_GOTO_ON_FALSE((emac->spi.ctx = emac->spi.init(dm9051_config)) != NULL, NULL, err, TAG, "SPI initialization failed"); ++ } ++ + /* create dm9051 task */ + BaseType_t core_num = tskNO_AFFINITY; + if (mac_config->flags & ETH_MAC_FLAG_PIN_TO_CORE) { +@@ -913,8 +944,8 @@ err: + if (emac->rx_task_hdl) { + vTaskDelete(emac->rx_task_hdl); + } +- if (emac->spi_lock) { +- vSemaphoreDelete(emac->spi_lock); ++ if (emac->spi.ctx) { ++ emac->spi.deinit(emac->spi.ctx); + } + heap_caps_free(emac->rx_buffer); + free(emac); +diff --git a/components/esp_eth/src/esp_eth_mac_ksz8851snl.c b/components/esp_eth/src/esp_eth_mac_ksz8851snl.c +index b6aea4df90ead8dc2162e0735bdc310717881c97..cda12f0159835ea1cb818736bdc2611056b131ff 100644 +--- a/components/esp_eth/src/esp_eth_mac_ksz8851snl.c ++++ b/components/esp_eth/src/esp_eth_mac_ksz8851snl.c +@@ -3,7 +3,7 @@ + * + * SPDX-License-Identifier: MIT + * +- * SPDX-FileContributor: 2021-2022 Espressif Systems (Shanghai) CO LTD ++ * SPDX-FileContributor: 2021-2023 Espressif Systems (Shanghai) CO LTD + */ + + #include +@@ -22,10 +22,22 @@ + + #define KSZ8851_ETH_MAC_RX_BUF_SIZE_AUTO (0) + ++typedef struct { ++ spi_device_handle_t hdl; ++} spi_info_t; ++ ++typedef struct { ++ void *ctx; ++ void *(*init)(const void *spi_config); ++ esp_err_t (*deinit)(void *spi_ctx); ++ esp_err_t (*read)(void *spi_ctx, uint32_t cmd,uint32_t addr, void *data, uint32_t data_len); ++ esp_err_t (*write)(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); ++} spi_interface_t; ++ + typedef struct { + esp_eth_mac_t parent; + esp_eth_mediator_t *eth; +- spi_device_handle_t spi_hdl; ++ spi_interface_t spi; + SemaphoreHandle_t spi_lock; + TaskHandle_t rx_task_hdl; + uint32_t sw_reset_timeout_ms; +@@ -73,6 +85,95 @@ IRAM_ATTR static void ksz8851_isr_handler(void *arg) + } + } + ++static void *ksz8851_spi_init(const void *spi_config) ++{ ++ void *ret = NULL; ++ eth_ksz8851snl_config_t *ksz8851snl_config = (eth_ksz8851snl_config_t *)spi_config; ++ spi_info_t *spi = calloc(1, sizeof(spi_info_t)); ++ ESP_GOTO_ON_FALSE(spi, NULL, err, TAG, "no memory for SPI context data"); ++ ++ // SPI device init ++ ESP_GOTO_ON_FALSE(spi_bus_add_device(ksz8851snl_config->spi_host_id, ksz8851snl_config->spi_devcfg, &spi->hdl) == ESP_OK, NULL, ++ err, TAG, "adding device to SPI host #%d failed", ksz8851snl_config->spi_host_id + 1); ++ ret = spi; ++ return ret; ++err: ++ if (spi) { ++ free(spi); ++ } ++ return ret; ++} ++ ++static esp_err_t ksz8851_spi_deinit(void *spi_ctx) ++{ ++ esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; ++ ++ spi_bus_remove_device(spi->hdl); ++ ++ free(spi); ++ return ret; ++} ++ ++static esp_err_t ksz8851_spi_read(void *spi_ctx, uint32_t cmd, uint32_t addr, void *value, uint32_t len) ++{ ++ esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; ++ ++ spi_transaction_ext_t trans = { ++ .base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY | (len <= 4 ? SPI_TRANS_USE_RXDATA : 0), ++ .base.cmd = cmd, ++ .base.addr = addr, ++ .base.length = 8 * len, ++ .base.rx_buffer = value, ++ .command_bits = KSZ8851_SPI_COMMAND_BITS ++ }; ++ if (cmd >= KSZ8851_SPI_COMMAND_READ_FIFO) { ++ trans.address_bits = 8 - KSZ8851_SPI_COMMAND_BITS; ++ } else { ++ trans.address_bits = 16 - KSZ8851_SPI_COMMAND_BITS; ++ } ++ ++ // No need for mutex here since SPI access is protected at higher layer of this driver ++ if (spi_device_polling_transmit(spi->hdl, &trans.base) != ESP_OK) { ++ ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); ++ ret = ESP_FAIL; ++ } ++ ++ if ((trans.base.flags & SPI_TRANS_USE_RXDATA) && len <= 4) { ++ memcpy(value, trans.base.rx_data, len); // copy register values to output ++ } ++ return ret; ++} ++ ++static esp_err_t ksz8851_spi_write(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *value, uint32_t len) ++{ ++ esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; ++ ++ spi_transaction_ext_t trans = { ++ .base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY, ++ .base.cmd = cmd, ++ .base.addr = addr, ++ .base.length = 8 * len, ++ .base.tx_buffer = value, ++ .command_bits = KSZ8851_SPI_COMMAND_BITS ++ }; ++ if (cmd >= KSZ8851_SPI_COMMAND_READ_FIFO) { ++ trans.address_bits = 8 - KSZ8851_SPI_COMMAND_BITS; ++ } else { ++ trans.address_bits = 16 - KSZ8851_SPI_COMMAND_BITS; ++ } ++ ++ // No need for mutex here since SPI access is protected at higher layer of this driver ++ if (spi_device_polling_transmit(spi->hdl, &trans.base) != ESP_OK) { ++ ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); ++ ret = ESP_FAIL; ++ } ++ ++ return ret; ++} ++ + static inline bool ksz8851_mutex_lock(emac_ksz8851snl_t *emac) + { + return xSemaphoreTakeRecursive(emac->spi_lock, pdMS_TO_TICKS(KSZ8851_SPI_LOCK_TIMEOUT_MS)) == pdTRUE; +@@ -83,70 +184,49 @@ static inline bool ksz8851_mutex_unlock(emac_ksz8851snl_t *emac) + return xSemaphoreGiveRecursive(emac->spi_lock) == pdTRUE; + } + +-static esp_err_t ksz8851_read_reg(emac_ksz8851snl_t *emac, uint32_t address, uint16_t *value) ++static esp_err_t ksz8851_read_reg(emac_ksz8851snl_t *emac, uint32_t reg_addr, uint16_t *value) + { + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(value != NULL, ESP_ERR_INVALID_ARG, err, TAG, "out pointer must not be null"); +- ESP_GOTO_ON_FALSE((address & ~KSZ8851_VALID_ADDRESS_MASK) == 0U, ESP_ERR_INVALID_ARG, err, TAG, "address is out of bounds"); ++ ESP_GOTO_ON_FALSE((reg_addr & ~KSZ8851_VALID_ADDRESS_MASK) == 0U, ESP_ERR_INVALID_ARG, err, TAG, "address is out of bounds"); + +- const unsigned data_size = 16U; // NOTE(v.chistyakov): bits + // NOTE(v.chistyakov): select upper or lower word inside a dword +- const unsigned byte_mask = 0x3U << (KSZ8851_SPI_BYTE_MASK_SHIFT + (address & 0x2U)); +- address <<= KSZ8851_SPI_ADDR_SHIFT; ++ const unsigned byte_mask = 0x3U << (KSZ8851_SPI_BYTE_MASK_SHIFT + (reg_addr & 0x2U)); ++ reg_addr <<= KSZ8851_SPI_ADDR_SHIFT; + +- spi_transaction_ext_t trans = { +- .base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY | SPI_TRANS_USE_RXDATA, +- .base.cmd = KSZ8851_SPI_COMMAND_READ_REG, +- .base.addr = address | byte_mask, +- .base.length = data_size, +- .command_bits = KSZ8851_SPI_COMMAND_BITS, +- .address_bits = 16 - KSZ8851_SPI_COMMAND_BITS, +- }; ++ // Need to protect SPI access at higher layer of the driver since once packet transmit/receive is started (`SDA Start DMA Access` bit is set), ++ // all registers access are disabled. + if (ksz8851_mutex_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans.base) != ESP_OK) { +- ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); +- ret = ESP_FAIL; +- } +- ksz8851_mutex_unlock(emac); +- memcpy(value, trans.base.rx_data, data_size >> 3U); +- ESP_LOGV(TAG, "reading reg 0x%02x == 0x%04x", address, *value); ++ ret = emac->spi.read(emac->spi.ctx, KSZ8851_SPI_COMMAND_READ_REG, reg_addr | byte_mask, value, 2); + } else { + ret = ESP_ERR_TIMEOUT; + } ++ ksz8851_mutex_unlock(emac); ++ ESP_LOGV(TAG, "reading reg 0x%02x == 0x%02x", reg_addr, *value); ++ + err: + return ret; + } + +-static esp_err_t ksz8851_write_reg(emac_ksz8851snl_t *emac, uint32_t address, uint16_t value) ++static esp_err_t ksz8851_write_reg(emac_ksz8851snl_t *emac, uint32_t reg_addr, uint16_t value) + { + esp_err_t ret = ESP_OK; +- ESP_GOTO_ON_FALSE((address & ~KSZ8851_VALID_ADDRESS_MASK) == 0U, ESP_ERR_INVALID_ARG, err, TAG, "address is out of bounds"); +- ESP_LOGV(TAG, "writing reg 0x%02x = 0x%04x", address, value); ++ ESP_GOTO_ON_FALSE((reg_addr & ~KSZ8851_VALID_ADDRESS_MASK) == 0U, ESP_ERR_INVALID_ARG, err, TAG, "address is out of bounds"); ++ ESP_LOGV(TAG, "writing reg 0x%02x = 0x%02x", reg_addr, value); + +- const unsigned data_size = 16U; // NOTE(v.chistyakov): bits + // NOTE(v.chistyakov): select upper or lower word inside a dword +- const unsigned byte_mask = 0x3U << (KSZ8851_SPI_BYTE_MASK_SHIFT + (address & 0x2U)); +- address <<= KSZ8851_SPI_ADDR_SHIFT; ++ const unsigned byte_mask = 0x3U << (KSZ8851_SPI_BYTE_MASK_SHIFT + (reg_addr & 0x2U)); ++ reg_addr <<= KSZ8851_SPI_ADDR_SHIFT; + +- spi_transaction_ext_t trans = { +- .base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY | SPI_TRANS_USE_TXDATA, +- .base.cmd = KSZ8851_SPI_COMMAND_WRITE_REG, +- .base.addr = address | byte_mask, +- .base.length = data_size, +- .command_bits = KSZ8851_SPI_COMMAND_BITS, +- .address_bits = 16 - KSZ8851_SPI_COMMAND_BITS, +- }; +- +- memcpy(trans.base.tx_data, &value, data_size >> 3U); ++ // Need to protect SPI access at higher layer of the driver since once packet transmit/receive is started (`SDA Start DMA Access` bit is set), ++ // all registers access are disabled. + if (ksz8851_mutex_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans.base) != ESP_OK) { +- ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); +- ret = ESP_FAIL; +- } +- ksz8851_mutex_unlock(emac); ++ ret = emac->spi.write(emac->spi.ctx, KSZ8851_SPI_COMMAND_WRITE_REG, reg_addr | byte_mask, &value, 2); + } else { + ret = ESP_ERR_TIMEOUT; + } ++ ksz8851_mutex_unlock(emac); ++ + err: + return ret; + } +@@ -313,6 +393,7 @@ static esp_err_t emac_ksz8851snl_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint + ESP_LOGV(TAG, "transmitting frame of size %u", length); + esp_err_t ret = ESP_OK; + emac_ksz8851snl_t *emac = __containerof(mac, emac_ksz8851snl_t, parent); ++ // Lock SPI since once `SDA Start DMA Access` bit is set, all registers access are disabled. + if (!ksz8851_mutex_lock(emac)) { + return ESP_ERR_TIMEOUT; + } +@@ -333,24 +414,12 @@ static esp_err_t emac_ksz8851snl_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint + emac->tx_buffer[3] = (length >> 8U) & 0xFFU; + memcpy(emac->tx_buffer + 4U, buf, length); + +- spi_transaction_ext_t trans = { +- .base.flags = SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_CMD, +- .base.cmd = KSZ8851_SPI_COMMAND_WRITE_FIFO, +- .base.length = transmit_length * 8U, // NOTE(v.chistyakov): bits +- .base.tx_buffer = emac->tx_buffer, +- .command_bits = 2U, +- .address_bits = 6U, +- }; +- + uint16_t ier; + ESP_GOTO_ON_ERROR(ksz8851_read_reg(emac, KSZ8851_IER, &ier), err, TAG, "IER read failed"); + ESP_GOTO_ON_ERROR(ksz8851_write_reg(emac, KSZ8851_IER, 0), err, TAG, "IER write failed"); + + ESP_GOTO_ON_ERROR(ksz8851_set_bits(emac, KSZ8851_RXQCR, RXQCR_SDA), err, TAG, "RXQCR write failed"); +- if (spi_device_polling_transmit(emac->spi_hdl, &trans.base) != ESP_OK) { +- ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); +- ret = ESP_FAIL; +- } ++ ret = emac->spi.write(emac->spi.ctx, KSZ8851_SPI_COMMAND_WRITE_FIFO, 0, emac->tx_buffer, transmit_length); + ESP_GOTO_ON_ERROR(ksz8851_clear_bits(emac, KSZ8851_RXQCR, RXQCR_SDA), err, TAG, "RXQCR write failed"); + + ESP_GOTO_ON_ERROR(ksz8851_write_reg(emac, KSZ8851_IER, ier), err, TAG, "IER write failed"); +@@ -438,23 +507,13 @@ static esp_err_t emac_ksz8851_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t + + // NOTE(v.chistyakov): 4 dummy + 4 header + alignment + const unsigned receive_size = 8U + ((byte_count + 3U) & ~0x3U); +- spi_transaction_ext_t trans = { +- .base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY, +- .base.cmd = KSZ8851_SPI_COMMAND_READ_FIFO, +- .base.length = receive_size * 8U, // NOTE(v.chistyakov): bits +- .base.rx_buffer = emac->rx_buffer, +- .command_bits = 2U, +- .address_bits = 6U, +- }; ++ // Lock SPI since once `SDA Start DMA Access` bit is set, all registers access are disabled. + if (!ksz8851_mutex_lock(emac)) { + return ESP_ERR_TIMEOUT; + } + ESP_GOTO_ON_ERROR(ksz8851_clear_bits(emac, KSZ8851_RXFDPR, RXFDPR_RXFP_MASK), err, TAG, "RXFDPR write failed"); + ESP_GOTO_ON_ERROR(ksz8851_set_bits(emac, KSZ8851_RXQCR, RXQCR_SDA), err, TAG, "RXQCR write failed"); +- if (spi_device_polling_transmit(emac->spi_hdl, &trans.base) != ESP_OK) { +- ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); +- ret = ESP_FAIL; +- } ++ ret = emac->spi.read(emac->spi.ctx, KSZ8851_SPI_COMMAND_READ_FIFO, 0, emac->rx_buffer, receive_size); + ESP_GOTO_ON_ERROR(ksz8851_clear_bits(emac, KSZ8851_RXQCR, RXQCR_SDA), err, TAG, "RXQCR write failed"); + ksz8851_mutex_unlock(emac); + // NOTE(v.chistyakov): skip 4 dummy, 4 header +@@ -728,7 +787,7 @@ static esp_err_t emac_ksz8851_del(esp_eth_mac_t *mac) + { + emac_ksz8851snl_t *emac = __containerof(mac, emac_ksz8851snl_t, parent); + vTaskDelete(emac->rx_task_hdl); +- spi_bus_remove_device(emac->spi_hdl); ++ emac->spi.deinit(emac->spi.ctx); + vSemaphoreDelete(emac->spi_lock); + heap_caps_free(emac->rx_buffer); + heap_caps_free(emac->tx_buffer); +@@ -748,10 +807,6 @@ esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851 + emac = calloc(1, sizeof(emac_ksz8851snl_t)); + ESP_GOTO_ON_FALSE(emac, NULL, err, TAG, "no mem for MAC instance"); + +- /* SPI device init */ +- ESP_GOTO_ON_FALSE(spi_bus_add_device(ksz8851snl_config->spi_host_id, ksz8851snl_config->spi_devcfg, &emac->spi_hdl) == ESP_OK, +- NULL, err, TAG, "adding device to SPI host #%d failed", ksz8851snl_config->spi_host_id + 1); +- + emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms; + emac->int_gpio_num = ksz8851snl_config->int_gpio_num; + emac->parent.set_mediator = emac_ksz8851_set_mediator; +@@ -772,8 +827,6 @@ esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851 + emac->parent.enable_flow_ctrl = emac_ksz8851_enable_flow_ctrl; + emac->parent.set_peer_pause_ability = emac_ksz8851_set_peer_pause_ability; + emac->parent.del = emac_ksz8851_del; +- emac->spi_lock = xSemaphoreCreateRecursiveMutex(); +- ESP_GOTO_ON_FALSE(emac->spi_lock, NULL, err, TAG, "create lock failed"); + emac->rx_buffer = NULL; + emac->tx_buffer = NULL; + emac->rx_buffer = heap_caps_malloc(KSZ8851_QMU_PACKET_LENGTH + KSZ8851_QMU_PACKET_PADDING, MALLOC_CAP_DMA); +@@ -781,6 +834,29 @@ esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851 + ESP_GOTO_ON_FALSE(emac->rx_buffer, NULL, err, TAG, "RX buffer allocation failed"); + ESP_GOTO_ON_FALSE(emac->tx_buffer, NULL, err, TAG, "TX buffer allocation failed"); + ++ /* create mutex */ ++ emac->spi_lock = xSemaphoreCreateRecursiveMutex(); ++ ESP_GOTO_ON_FALSE(emac->spi_lock, NULL, err, TAG, "create lock failed"); ++ ++ if (ksz8851snl_config->custom_spi_driver.init != NULL && ksz8851snl_config->custom_spi_driver.deinit != NULL ++ && ksz8851snl_config->custom_spi_driver.read != NULL && ksz8851snl_config->custom_spi_driver.write != NULL) { ++ ESP_LOGD(TAG, "Using user's custom SPI Driver"); ++ emac->spi.init = ksz8851snl_config->custom_spi_driver.init; ++ emac->spi.deinit = ksz8851snl_config->custom_spi_driver.deinit; ++ emac->spi.read = ksz8851snl_config->custom_spi_driver.read; ++ emac->spi.write = ksz8851snl_config->custom_spi_driver.write; ++ /* Custom SPI driver device init */ ++ ESP_GOTO_ON_FALSE((emac->spi.ctx = emac->spi.init(ksz8851snl_config->custom_spi_driver.config)) != NULL, NULL, err, TAG, "SPI initialization failed"); ++ } else { ++ ESP_LOGD(TAG, "Using default SPI Driver"); ++ emac->spi.init = ksz8851_spi_init; ++ emac->spi.deinit = ksz8851_spi_deinit; ++ emac->spi.read = ksz8851_spi_read; ++ emac->spi.write = ksz8851_spi_write; ++ /* SPI device init */ ++ ESP_GOTO_ON_FALSE((emac->spi.ctx = emac->spi.init(ksz8851snl_config)) != NULL, NULL, err, TAG, "SPI initialization failed"); ++ } ++ + BaseType_t core_num = tskNO_AFFINITY; + if (mac_config->flags & ETH_MAC_FLAG_PIN_TO_CORE) { + core_num = esp_cpu_get_core_id(); +@@ -798,6 +874,9 @@ err: + if (emac->spi_lock) { + vSemaphoreDelete(emac->spi_lock); + } ++ if (emac->spi.ctx) { ++ emac->spi.deinit(emac->spi.ctx); ++ } + // NOTE(v.chistyakov): safe to call with NULL + heap_caps_free(emac->rx_buffer); + heap_caps_free(emac->tx_buffer); +diff --git a/components/esp_eth/src/esp_eth_mac_w5500.c b/components/esp_eth/src/esp_eth_mac_w5500.c +index 7a7708d0ca8bbbf77b32d9cb01ce34e57cc1f242..5b19d5cfcdfc67105809cbca33e780850b9d4fea 100644 +--- a/components/esp_eth/src/esp_eth_mac_w5500.c ++++ b/components/esp_eth/src/esp_eth_mac_w5500.c +@@ -37,11 +37,23 @@ typedef struct { + uint32_t remain; + }__attribute__((packed)) emac_w5500_auto_buf_info_t; + ++typedef struct { ++ spi_device_handle_t hdl; ++ SemaphoreHandle_t lock; ++} spi_info_t; ++ ++typedef struct { ++ void *ctx; ++ void *(*init)(const void *spi_config); ++ esp_err_t (*deinit)(void *spi_ctx); ++ esp_err_t (*read)(void *spi_ctx, uint32_t cmd,uint32_t addr, void *data, uint32_t data_len); ++ esp_err_t (*write)(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); ++} spi_interface_t; ++ + typedef struct { + esp_eth_mac_t parent; + esp_eth_mediator_t *eth; +- spi_device_handle_t spi_hdl; +- SemaphoreHandle_t spi_lock; ++ spi_interface_t spi; + TaskHandle_t rx_task_hdl; + uint32_t sw_reset_timeout_ms; + int int_gpio_num; +@@ -50,64 +62,132 @@ typedef struct { + uint8_t *rx_buffer; + } emac_w5500_t; + +-static inline bool w5500_lock(emac_w5500_t *emac) ++static void *w5500_spi_init(const void *spi_config) + { +- return xSemaphoreTake(emac->spi_lock, pdMS_TO_TICKS(W5500_SPI_LOCK_TIMEOUT_MS)) == pdTRUE; ++ void *ret = NULL; ++ eth_w5500_config_t *w5500_config = (eth_w5500_config_t *)spi_config; ++ spi_info_t *spi = calloc(1, sizeof(spi_info_t)); ++ ESP_GOTO_ON_FALSE(spi, NULL, err, TAG, "no memory for SPI context data"); ++ ++ /* SPI device init */ ++ spi_device_interface_config_t spi_devcfg; ++ spi_devcfg = *(w5500_config->spi_devcfg); ++ if (w5500_config->spi_devcfg->command_bits == 0 && w5500_config->spi_devcfg->address_bits == 0) { ++ /* configure default SPI frame format */ ++ spi_devcfg.command_bits = 16; // Actually it's the address phase in W5500 SPI frame ++ spi_devcfg.address_bits = 8; // Actually it's the control phase in W5500 SPI frame ++ } else { ++ ESP_GOTO_ON_FALSE(w5500_config->spi_devcfg->command_bits == 16 && w5500_config->spi_devcfg->address_bits == 8, ++ NULL, err, TAG, "incorrect SPI frame format (command_bits/address_bits)"); ++ } ++ ESP_GOTO_ON_FALSE(spi_bus_add_device(w5500_config->spi_host_id, &spi_devcfg, &spi->hdl) == ESP_OK, NULL, ++ err, TAG, "adding device to SPI host #%d failed", w5500_config->spi_host_id + 1); ++ /* create mutex */ ++ spi->lock = xSemaphoreCreateMutex(); ++ ESP_GOTO_ON_FALSE(spi->lock, NULL, err, TAG, "create lock failed"); ++ ++ ret = spi; ++ return ret; ++err: ++ if (spi) { ++ if (spi->lock) { ++ vSemaphoreDelete(spi->lock); ++ } ++ free(spi); ++ } ++ return ret; + } + +-static inline bool w5500_unlock(emac_w5500_t *emac) ++static esp_err_t w5500_spi_deinit(void *spi_ctx) + { +- return xSemaphoreGive(emac->spi_lock) == pdTRUE; ++ esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; ++ ++ spi_bus_remove_device(spi->hdl); ++ vSemaphoreDelete(spi->lock); ++ ++ free(spi); ++ return ret; + } + +-static esp_err_t w5500_write(emac_w5500_t *emac, uint32_t address, const void *value, uint32_t len) ++static inline bool w5500_spi_lock(spi_info_t *spi) ++{ ++ return xSemaphoreTake(spi->lock, pdMS_TO_TICKS(W5500_SPI_LOCK_TIMEOUT_MS)) == pdTRUE; ++} ++ ++static inline bool w5500_spi_unlock(spi_info_t *spi) ++{ ++ return xSemaphoreGive(spi->lock) == pdTRUE; ++} ++ ++static esp_err_t w5500_spi_write(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *value, uint32_t len) + { + esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; + + spi_transaction_t trans = { +- .cmd = (address >> W5500_ADDR_OFFSET), +- .addr = ((address & 0xFFFF) | (W5500_ACCESS_MODE_WRITE << W5500_RWB_OFFSET) | W5500_SPI_OP_MODE_VDM), ++ .cmd = cmd, ++ .addr = addr, + .length = 8 * len, + .tx_buffer = value + }; +- if (w5500_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { ++ if (w5500_spi_lock(spi)) { ++ if (spi_device_polling_transmit(spi->hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } +- w5500_unlock(emac); ++ w5500_spi_unlock(spi); + } else { + ret = ESP_ERR_TIMEOUT; + } + return ret; + } + +-static esp_err_t w5500_read(emac_w5500_t *emac, uint32_t address, void *value, uint32_t len) ++static esp_err_t w5500_spi_read(void *spi_ctx, uint32_t cmd, uint32_t addr, void *value, uint32_t len) + { + esp_err_t ret = ESP_OK; ++ spi_info_t *spi = (spi_info_t *)spi_ctx; + + spi_transaction_t trans = { + .flags = len <= 4 ? SPI_TRANS_USE_RXDATA : 0, // use direct reads for registers to prevent overwrites by 4-byte boundary writes +- .cmd = (address >> W5500_ADDR_OFFSET), +- .addr = ((address & 0xFFFF) | (W5500_ACCESS_MODE_READ << W5500_RWB_OFFSET) | W5500_SPI_OP_MODE_VDM), ++ .cmd = cmd, ++ .addr = addr, + .length = 8 * len, + .rx_buffer = value + }; +- if (w5500_lock(emac)) { +- if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) { ++ if (w5500_spi_lock(spi)) { ++ if (spi_device_polling_transmit(spi->hdl, &trans) != ESP_OK) { + ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__); + ret = ESP_FAIL; + } +- w5500_unlock(emac); ++ w5500_spi_unlock(spi); + } else { + ret = ESP_ERR_TIMEOUT; + } +- if ((trans.flags&SPI_TRANS_USE_RXDATA) && len <= 4) { ++ if ((trans.flags & SPI_TRANS_USE_RXDATA) && len <= 4) { + memcpy(value, trans.rx_data, len); // copy register values to output + } + return ret; + } + ++static esp_err_t w5500_read(emac_w5500_t *emac, uint32_t address, void *data, uint32_t len) ++{ ++ uint32_t cmd = (address >> W5500_ADDR_OFFSET); // Actually it's the address phase in W5500 SPI frame ++ uint32_t addr = ((address & 0xFFFF) | (W5500_ACCESS_MODE_READ << W5500_RWB_OFFSET) ++ | W5500_SPI_OP_MODE_VDM); // Actually it's the command phase in W5500 SPI frame ++ ++ return emac->spi.read(emac->spi.ctx, cmd, addr, data, len); ++} ++ ++static esp_err_t w5500_write(emac_w5500_t *emac, uint32_t address, const void *data, uint32_t len) ++{ ++ uint32_t cmd = (address >> W5500_ADDR_OFFSET); // Actually it's the address phase in W5500 SPI frame ++ uint32_t addr = ((address & 0xFFFF) | (W5500_ACCESS_MODE_WRITE << W5500_RWB_OFFSET) ++ | W5500_SPI_OP_MODE_VDM); // Actually it's the command phase in W5500 SPI frame ++ ++ return emac->spi.write(emac->spi.ctx, cmd, addr, data, len); ++} ++ + static esp_err_t w5500_send_command(emac_w5500_t *emac, uint8_t command, uint32_t timeout_ms) + { + esp_err_t ret = ESP_OK; +@@ -738,8 +818,7 @@ static esp_err_t emac_w5500_del(esp_eth_mac_t *mac) + { + emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent); + vTaskDelete(emac->rx_task_hdl); +- spi_bus_remove_device(emac->spi_hdl); +- vSemaphoreDelete(emac->spi_lock); ++ emac->spi.deinit(emac->spi.ctx); + heap_caps_free(emac->rx_buffer); + free(emac); + return ESP_OK; +@@ -754,19 +833,6 @@ esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, con + ESP_GOTO_ON_FALSE(emac, NULL, err, TAG, "no mem for MAC instance"); + /* w5500 driver is interrupt driven */ + ESP_GOTO_ON_FALSE(w5500_config->int_gpio_num >= 0, NULL, err, TAG, "invalid interrupt gpio number"); +- /* SPI device init */ +- spi_device_interface_config_t spi_devcfg; +- memcpy(&spi_devcfg, w5500_config->spi_devcfg, sizeof(spi_device_interface_config_t)); +- if (w5500_config->spi_devcfg->command_bits == 0 && w5500_config->spi_devcfg->address_bits == 0) { +- /* configure default SPI frame format */ +- spi_devcfg.command_bits = 16; // Actually it's the address phase in W5500 SPI frame +- spi_devcfg.address_bits = 8; // Actually it's the control phase in W5500 SPI frame +- } else { +- ESP_GOTO_ON_FALSE(w5500_config->spi_devcfg->command_bits == 16 || w5500_config->spi_devcfg->address_bits == 8, +- NULL, err, TAG, "incorrect SPI frame format (command_bits/address_bits)"); +- } +- ESP_GOTO_ON_FALSE(spi_bus_add_device(w5500_config->spi_host_id, &spi_devcfg, &emac->spi_hdl) == ESP_OK, +- NULL, err, TAG, "adding device to SPI host #%d failed", w5500_config->spi_host_id + 1); + /* bind methods and attributes */ + emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms; + emac->int_gpio_num = w5500_config->int_gpio_num; +@@ -788,9 +854,26 @@ esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, con + emac->parent.enable_flow_ctrl = emac_w5500_enable_flow_ctrl; + emac->parent.transmit = emac_w5500_transmit; + emac->parent.receive = emac_w5500_receive; +- /* create mutex */ +- emac->spi_lock = xSemaphoreCreateMutex(); +- ESP_GOTO_ON_FALSE(emac->spi_lock, NULL, err, TAG, "create lock failed"); ++ ++ if (w5500_config->custom_spi_driver.init != NULL && w5500_config->custom_spi_driver.deinit != NULL ++ && w5500_config->custom_spi_driver.read != NULL && w5500_config->custom_spi_driver.write != NULL) { ++ ESP_LOGD(TAG, "Using user's custom SPI Driver"); ++ emac->spi.init = w5500_config->custom_spi_driver.init; ++ emac->spi.deinit = w5500_config->custom_spi_driver.deinit; ++ emac->spi.read = w5500_config->custom_spi_driver.read; ++ emac->spi.write = w5500_config->custom_spi_driver.write; ++ /* Custom SPI driver device init */ ++ ESP_GOTO_ON_FALSE((emac->spi.ctx = emac->spi.init(w5500_config->custom_spi_driver.config)) != NULL, NULL, err, TAG, "SPI initialization failed"); ++ } else { ++ ESP_LOGD(TAG, "Using default SPI Driver"); ++ emac->spi.init = w5500_spi_init; ++ emac->spi.deinit = w5500_spi_deinit; ++ emac->spi.read = w5500_spi_read; ++ emac->spi.write = w5500_spi_write; ++ /* SPI device init */ ++ ESP_GOTO_ON_FALSE((emac->spi.ctx = emac->spi.init(w5500_config)) != NULL, NULL, err, TAG, "SPI initialization failed"); ++ } ++ + /* create w5500 task */ + BaseType_t core_num = tskNO_AFFINITY; + if (mac_config->flags & ETH_MAC_FLAG_PIN_TO_CORE) { +@@ -810,8 +893,8 @@ err: + if (emac->rx_task_hdl) { + vTaskDelete(emac->rx_task_hdl); + } +- if (emac->spi_lock) { +- vSemaphoreDelete(emac->spi_lock); ++ if (emac->spi.ctx) { ++ emac->spi.deinit(emac->spi.ctx); + } + heap_caps_free(emac->rx_buffer); + free(emac); diff --git a/tools/add_sdk_json.py b/tools/add_sdk_json.py new file mode 100644 index 000000000..d2deb4a87 --- /dev/null +++ b/tools/add_sdk_json.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +from __future__ import print_function + +__author__ = "Hristo Gochkov" +__version__ = "2023" + +import os +import shutil +import errno +import os.path +import json +import platform +import sys +import stat +import argparse + +if sys.version_info[0] == 3: + unicode = lambda s: str(s) + +def add_system(systems, host, url, filename, sha, size): + system = { + "host": host, + "url": url, + "archiveFileName": filename, + "checksum": "SHA-256:"+sha, + "size": str(size) + } + systems.append(system) + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + prog = 'add_sdk_json', + description = 'Update SDK in Arduino package index') + parser.add_argument('-j', '--pkg-json', dest='arduino_json', required=True, help='path to package json') + parser.add_argument('-n', '--name', dest='tool_name', required=True, help='name of the SDK package') + parser.add_argument('-v', '--version', dest='tool_version', required=True, help='version of the new SDK') + parser.add_argument('-u', '--url', dest='tool_url', required=True, help='url to the zip of the new SDK') + parser.add_argument('-f', '--filename', dest='tool_filename', required=True, help='filename of the zip of the new SDK') + parser.add_argument('-s', '--size', dest='tool_size', required=True, help='size of the zip of the new SDK') + parser.add_argument('-c', '--sha', dest='tool_sha', required=True, help='sha256 of the zip of the new SDK') + args = parser.parse_args() + + print('Destination : {0}.'.format(args.arduino_json)) + print('Tool Name : {0}.'.format(args.tool_name)) + print('Tool Version : {0}.'.format(args.tool_version)) + print('Tool URL : {0}.'.format(args.tool_url)) + print('Tool File Name: {0}.'.format(args.tool_filename)) + print('Tool Size : {0}.'.format(args.tool_size)) + print('Tool SHA256 : {0}.'.format(args.tool_sha)) + + arduino_json = args.arduino_json; + tool_name = args.tool_name; + tool_version = args.tool_version; + tool_url = args.tool_url; + tool_filename = args.tool_filename; + tool_size = args.tool_size; + tool_sha = args.tool_sha; + + # code start + farray = {"packages":[{"platforms":[{"toolsDependencies":[]}],"tools":[]}]} + if os.path.isfile(arduino_json) == True: + farray = json.load(open(arduino_json)) + + dep_found = False + dep_skip = False + for dep in farray['packages'][0]['platforms'][0]['toolsDependencies']: + if dep['name'] == tool_name: + if dep['version'] == tool_version: + print('Skipping {0}. Same version {1}'.format(tool_name, tool_version)) + dep_skip = True + break + print('Updating dependency version of {0} from {1} to {2}'.format(tool_name, dep['version'], tool_version)) + dep['version'] = tool_version + dep_found = True + break + + if dep_skip == False: + if dep_found == False: + print('Adding new dependency: {0} version {1}'.format(tool_name, tool_version)) + deps = { + "packager": "esp32", + "name": tool_name, + "version": tool_version + } + farray['packages'][0]['platforms'][0]['toolsDependencies'].append(deps) + + systems = [] + add_system(systems, "i686-mingw32", tool_url, tool_filename, tool_sha, tool_size) + add_system(systems, "x86_64-mingw32", tool_url, tool_filename, tool_sha, tool_size) + add_system(systems, "arm64-apple-darwin", tool_url, tool_filename, tool_sha, tool_size) + add_system(systems, "x86_64-apple-darwin", tool_url, tool_filename, tool_sha, tool_size) + add_system(systems, "x86_64-pc-linux-gnu", tool_url, tool_filename, tool_sha, tool_size) + add_system(systems, "i686-pc-linux-gnu", tool_url, tool_filename, tool_sha, tool_size) + add_system(systems, "aarch64-linux-gnu", tool_url, tool_filename, tool_sha, tool_size) + add_system(systems, "arm-linux-gnueabihf", tool_url, tool_filename, tool_sha, tool_size) + + tool_found = False + for t in farray['packages'][0]['tools']: + if t['name'] == tool_name: + t['version'] = tool_version + t['systems'] = systems + tool_found = True + print('Updating systems of {0} to version {1}'.format(tool_name, tool_version)) + break + + if tool_found == False: + print('Adding new tool: {0} version {1}'.format(tool_name, tool_version)) + tools = { + "name": tool_name, + "version": tool_version, + "systems": systems + } + farray['packages'][0]['tools'].append(tools) + + json_str = json.dumps(farray, indent=2) + with open(arduino_json, "w") as f: + f.write(json_str+"\n") + f.close() + # print(json_str) + print('{0} generated'.format(arduino_json)) diff --git a/tools/archive-build.sh b/tools/archive-build.sh index 432f69031..f973a42ef 100755 --- a/tools/archive-build.sh +++ b/tools/archive-build.sh @@ -2,15 +2,11 @@ IDF_COMMIT=$(git -C "$IDF_PATH" rev-parse --short HEAD || echo "") IDF_BRANCH=$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD || echo "") - idf_version_string=${IDF_BRANCH//\//_}"-$IDF_COMMIT" -archive_path="dist/arduino-esp32-libs-$idf_version_string.tar.gz" -build_archive_path="dist/arduino-esp32-build-$idf_version_string.tar.gz" -mkdir -p dist && rm -rf "$archive_path" "$build_archive_path" +archive_path="dist/arduino-esp32-libs-$1-$idf_version_string.tar.gz" + +mkdir -p dist && rm -rf "$archive_path" if [ -d "out" ]; then cd out && tar zcf "../$archive_path" * && cd .. fi -if [ -d "build" ]; then - cd build && tar zcf "../$build_archive_path" * && cd .. -fi diff --git a/tools/check-deploy-needed.sh b/tools/check-deploy-needed.sh new file mode 100755 index 000000000..52401942a --- /dev/null +++ b/tools/check-deploy-needed.sh @@ -0,0 +1,85 @@ +#/bin/bash + +source ./tools/config.sh + +IDF_COMMIT=`github_last_commit "$IDF_REPO" "$IDF_BRANCH"` + +if [ -z $GITHUB_HEAD_REF ]; then + current_branch=`git branch --show-current` +else + current_branch="$GITHUB_HEAD_REF" +fi + +AR_BRANCH="master" +if [[ "$current_branch" != "master" && `github_branch_exists "$AR_REPO" "$current_branch"` == "1" ]]; then + AR_BRANCH="$current_branch" +else + AR_BRANCH_NAME="idf-$IDF_BRANCH" + has_ar_branch=`github_branch_exists "$AR_REPO" "$AR_BRANCH_NAME"` + if [ "$has_ar_branch" == "1" ]; then + AR_BRANCH="$AR_BRANCH_NAME" + else + has_ar_branch=`github_branch_exists "$AR_REPO" "$AR_PR_TARGET_BRANCH"` + if [ "$has_ar_branch" == "1" ]; then + AR_BRANCH="$AR_PR_TARGET_BRANCH" + fi + fi +fi + +# format new branch name and pr title +AR_NEW_BRANCH_NAME="idf-$IDF_BRANCH" +AR_NEW_COMMIT_MESSAGE="IDF $IDF_BRANCH $IDF_COMMIT" +AR_NEW_PR_TITLE="IDF $IDF_BRANCH" + +LIBS_VERSION="idf-"${IDF_BRANCH//\//_}"-$IDF_COMMIT" + +AR_HAS_BRANCH=`github_branch_exists "$AR_REPO" "$AR_NEW_BRANCH_NAME"` +if [ "$AR_HAS_BRANCH" == "1" ]; then + AR_HAS_COMMIT=`github_commit_exists "$AR_REPO" "$AR_NEW_BRANCH_NAME" "$IDF_COMMIT"` +else + AR_HAS_COMMIT=`github_commit_exists "$AR_REPO" "$AR_BRANCH" "$IDF_COMMIT"` +fi +AR_HAS_PR=`github_pr_exists "$AR_REPO" "$AR_NEW_BRANCH_NAME"` + +LIBS_HAS_BRANCH=`github_branch_exists "$AR_LIBS_REPO" "$AR_NEW_BRANCH_NAME"` +LIBS_HAS_COMMIT=`github_commit_exists "$AR_LIBS_REPO" "$AR_NEW_BRANCH_NAME" "$IDF_COMMIT"` + +export IDF_COMMIT + +export AR_NEW_BRANCH_NAME +export AR_NEW_COMMIT_MESSAGE +export AR_NEW_PR_TITLE + +export AR_HAS_COMMIT +export AR_HAS_BRANCH +export AR_HAS_PR + +export LIBS_VERSION +export LIBS_HAS_COMMIT +export LIBS_HAS_BRANCH + +echo "IDF_COMMIT: $IDF_COMMIT" +echo "AR_BRANCH: $AR_BRANCH" +echo "AR_NEW_COMMIT_MESSAGE: $AR_NEW_COMMIT_MESSAGE" +echo "AR_NEW_BRANCH_NAME: $AR_NEW_BRANCH_NAME" +echo "AR_NEW_PR_TITLE: $AR_NEW_PR_TITLE" +echo "AR_HAS_COMMIT: $AR_HAS_COMMIT" +echo "AR_HAS_BRANCH: $AR_HAS_BRANCH" +echo "AR_HAS_PR: $AR_HAS_PR" +echo "LIBS_VERSION: $LIBS_VERSION" +echo "LIBS_HAS_COMMIT: $LIBS_HAS_COMMIT" +echo "LIBS_HAS_BRANCH: $LIBS_HAS_BRANCH" + +if [ ! -x $GITHUB_OUTPUT ]; then + echo "idf_commit=$IDF_COMMIT" >> "$GITHUB_OUTPUT" + echo "ar_branch=$AR_BRANCH" >> "$GITHUB_OUTPUT" + echo "ar_new_commit_message=$AR_NEW_COMMIT_MESSAGE" >> "$GITHUB_OUTPUT" + echo "ar_new_branch_name=$AR_NEW_BRANCH_NAME" >> "$GITHUB_OUTPUT" + echo "ar_new_pr_title=$AR_NEW_PR_TITLE" >> "$GITHUB_OUTPUT" + echo "ar_has_commit=$AR_HAS_COMMIT" >> "$GITHUB_OUTPUT" + echo "ar_has_branch=$AR_HAS_BRANCH" >> "$GITHUB_OUTPUT" + echo "ar_has_pr=$AR_HAS_PR" >> "$GITHUB_OUTPUT" + echo "libs_version=$LIBS_VERSION" >> "$GITHUB_OUTPUT" + echo "libs_has_commit=$LIBS_HAS_COMMIT" >> "$GITHUB_OUTPUT" + echo "libs_has_branch=$LIBS_HAS_BRANCH" >> "$GITHUB_OUTPUT" +fi diff --git a/tools/config.sh b/tools/config.sh index e3f739800..54faa1f93 100755 --- a/tools/config.sh +++ b/tools/config.sh @@ -2,40 +2,42 @@ if [ -z $IDF_PATH ]; then - export IDF_PATH="$PWD/esp-idf" + export IDF_PATH="$PWD/esp-idf" fi if [ -z $IDF_BRANCH ]; then - IDF_BRANCH="release/v4.4" + IDF_BRANCH="release/v5.1" fi if [ -z $AR_PR_TARGET_BRANCH ]; then - AR_PR_TARGET_BRANCH="release/v2.x" + AR_PR_TARGET_BRANCH="master" fi if [ -z $IDF_TARGET ]; then - if [ -f sdkconfig ]; then - IDF_TARGET=`cat sdkconfig | grep CONFIG_IDF_TARGET= | cut -d'"' -f2` - if [ "$IDF_TARGET" = "" ]; then - IDF_TARGET="esp32" - fi - else - IDF_TARGET="esp32" - fi + if [ -f sdkconfig ]; then + IDF_TARGET=`cat sdkconfig | grep CONFIG_IDF_TARGET= | cut -d'"' -f2` + if [ "$IDF_TARGET" = "" ]; then + IDF_TARGET="esp32" + fi + else + IDF_TARGET="esp32" + fi fi -IDF_COMPS="$IDF_PATH/components" -IDF_TOOLCHAIN="xtensa-$IDF_TARGET-elf" - # Owner of the target ESP32 Arduino repository AR_USER="espressif" # The full name of the repository AR_REPO="$AR_USER/arduino-esp32" +IDF_REPO="$AR_USER/esp-idf" +AR_LIBS_REPO="$AR_USER/esp32-arduino-libs" AR_REPO_URL="https://github.com/$AR_REPO.git" +IDF_REPO_URL="https://github.com/$IDF_REPO.git" +AR_LIBS_REPO_URL="https://github.com/$AR_LIBS_REPO.git" if [ -n $GITHUB_TOKEN ]; then - AR_REPO_URL="https://$GITHUB_TOKEN@github.com/$AR_REPO.git" + AR_REPO_URL="https://$GITHUB_TOKEN@github.com/$AR_REPO.git" + AR_LIBS_REPO_URL="https://$GITHUB_TOKEN@github.com/$AR_LIBS_REPO.git" fi AR_ROOT="$PWD" @@ -44,30 +46,38 @@ AR_OUT="$AR_ROOT/out" AR_TOOLS="$AR_OUT/tools" AR_PLATFORM_TXT="$AR_OUT/platform.txt" AR_GEN_PART_PY="$AR_TOOLS/gen_esp32part.py" -AR_SDK="$AR_TOOLS/sdk/$IDF_TARGET" +AR_SDK="$AR_TOOLS/esp32-arduino-libs/$IDF_TARGET" +PIO_SDK="FRAMEWORK_SDK_DIR, \"$IDF_TARGET\"" +TOOLS_JSON_OUT="$AR_TOOLS/esp32-arduino-libs" +IDF_LIBS_DIR="$AR_ROOT/../esp32-arduino-libs" + +if [ -d "$IDF_PATH" ]; then + export IDF_COMMIT=$(git -C "$IDF_PATH" rev-parse --short HEAD) + export IDF_BRANCH=$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD) +fi function get_os(){ - OSBITS=`arch` - if [[ "$OSTYPE" == "linux"* ]]; then + OSBITS=`arch` + if [[ "$OSTYPE" == "linux"* ]]; then if [[ "$OSBITS" == "i686" ]]; then - echo "linux32" + echo "linux32" elif [[ "$OSBITS" == "x86_64" ]]; then - echo "linux64" + echo "linux64" elif [[ "$OSBITS" == "armv7l" ]]; then - echo "linux-armel" + echo "linux-armel" else - echo "unknown" - return 1 + echo "unknown" + return 1 fi - elif [[ "$OSTYPE" == "darwin"* ]]; then - echo "macos" - elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then - echo "win32" - else - echo "$OSTYPE" - return 1 - fi - return 0 + elif [[ "$OSTYPE" == "darwin"* ]]; then + echo "macos" + elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then + echo "win32" + else + echo "$OSTYPE" + return 1 + fi + return 0 } AR_OS=`get_os` @@ -76,54 +86,84 @@ export SED="sed" export SSTAT="stat -c %s" if [[ "$AR_OS" == "macos" ]]; then - if ! [ -x "$(command -v gsed)" ]; then - echo "ERROR: gsed is not installed! Please install gsed first. ex. brew install gsed" - exit 1 - fi - if ! [ -x "$(command -v gawk)" ]; then - echo "ERROR: gawk is not installed! Please install gawk first. ex. brew install gawk" - exit 1 - fi - export SED="gsed" - export SSTAT="stat -f %z" + if ! [ -x "$(command -v gsed)" ]; then + echo "ERROR: gsed is not installed! Please install gsed first. ex. brew install gsed" + exit 1 + fi + if ! [ -x "$(command -v gawk)" ]; then + echo "ERROR: gawk is not installed! Please install gawk first. ex. brew install gawk" + exit 1 + fi + export SED="gsed" + export SSTAT="stat -f %z" fi -function git_commit_exists(){ #git_commit_exists - local repo_path="$1" - local commit_message="$2" - local commits_found=`git -C "$repo_path" log --all --grep="$commit_message" | grep commit` - if [ -n "$commits_found" ]; then echo 1; else echo 0; fi +function github_commit_exists(){ #github_commit_exists + local repo_path="$1" + local branch_name="$2" + local commit_message="$3" + local commits_found=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" "https://api.github.com/repos/$repo_path/commits?sha=$branch_name" | jq -r '.[].commit.message' | grep "$commit_message" | wc -l` + if [ ! "$commits_found" == "" ] && [ ! "$commits_found" == "null" ] && [ ! "$commits_found" == "0" ]; then echo $commits_found; else echo 0; fi +} + +function github_last_commit(){ # github_last_commit + local repo_path="$1" + local branch_name="$2" + local commit=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" "https://api.github.com/repos/$repo_path/commits/heads/$branch_name" | jq -r '.sha'` + if [ ! "$commit" == "" ] && [ ! "$commit" == "null" ]; then + echo ${commit:0:8} + else + echo "" + fi +} + +function github_branch_exists(){ # github_branch_exists + local repo_path="$1" + local branch_name="$2" + local branch=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" "https://api.github.com/repos/$repo_path/branches/$branch_name" | jq -r '.name'` + if [ "$branch" == "$branch_name" ]; then echo 1; else echo 0; fi +} + +function github_pr_exists(){ # github_pr_exists + local repo_path="$1" + local branch_name="$2" + local pr_num=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" "https://api.github.com/repos/$repo_path/pulls?head=$AR_USER:$branch_name&state=open" | jq -r '.[].number'` + if [ ! "$pr_num" == "" ] && [ ! "$pr_num" == "null" ]; then echo 1; else echo 0; fi } + + function git_branch_exists(){ # git_branch_exists - local repo_path="$1" - local branch_name="$2" - local branch_found=`git -C "$repo_path" ls-remote --heads origin "$branch_name"` - if [ -n "$branch_found" ]; then echo 1; else echo 0; fi + local repo_path="$1" + local branch_name="$2" + local branch_found=`git -C "$repo_path" ls-remote --heads origin "$branch_name"` + if [ -n "$branch_found" ]; then echo 1; else echo 0; fi } -function git_pr_exists(){ # git_pr_exists - local pr_num=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" "https://api.github.com/repos/$AR_REPO/pulls?head=$AR_USER:$1&state=open" | jq -r '.[].number'` - if [ ! "$pr_num" == "" ] && [ ! "$pr_num" == "null" ]; then echo 1; else echo 0; fi +function git_commit_exists(){ #git_commit_exists + local repo_path="$1" + local commit_message="$2" + local commits_found=`git -C "$repo_path" log --all --grep="$commit_message" | grep commit` + if [ -n "$commits_found" ]; then echo 1; else echo 0; fi } function git_create_pr(){ # git_create_pr - local pr_branch="$1" - local pr_title="$2" - local pr_target="$3" - local pr_body="" - pr_body+="esp-idf: "$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD)" "$(git -C "$IDF_PATH" rev-parse --short HEAD)"\r\n" - for component in `ls "$AR_COMPS"`; do - if [ ! $component == "arduino" ]; then - if [ -d "$AR_COMPS/$component/.git" ] || [ -d "$AR_COMPS/$component/.github" ]; then - pr_body+="$component: "$(git -C "$AR_COMPS/$component" symbolic-ref --short HEAD || git -C "$AR_COMPS/$component" tag --points-at HEAD)" "$(git -C "$AR_COMPS/$component" rev-parse --short HEAD)"\r\n" - fi - fi - done - pr_body+="tinyusb: "$(git -C "$AR_COMPS/arduino_tinyusb/tinyusb" symbolic-ref --short HEAD || git -C "$AR_COMPS/arduino_tinyusb/tinyusb" tag --points-at HEAD)" "$(git -C "$AR_COMPS/arduino_tinyusb/tinyusb" rev-parse --short HEAD)"\r\n" - local pr_data="{\"title\": \"$pr_title\", \"body\": \"$pr_body\", \"head\": \"$AR_USER:$pr_branch\", \"base\": \"$pr_target\"}" - git_create_pr_res=`echo "$pr_data" | curl -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" --data @- "https://api.github.com/repos/$AR_REPO/pulls"` - local done_pr=`echo "$git_create_pr_res" | jq -r '.title'` - if [ ! "$done_pr" == "" ] && [ ! "$done_pr" == "null" ]; then echo 1; else echo 0; fi + local pr_branch="$1" + local pr_title="$2" + local pr_target="$3" + local pr_body="" + pr_body+="esp-idf: "$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD)" "$(git -C "$IDF_PATH" rev-parse --short HEAD)"\r\n" + for component in `ls "$AR_COMPS"`; do + if [ ! $component == "arduino" ]; then + if [ -d "$AR_COMPS/$component/.git" ] || [ -d "$AR_COMPS/$component/.github" ]; then + pr_body+="$component: "$(git -C "$AR_COMPS/$component" symbolic-ref --short HEAD || git -C "$AR_COMPS/$component" tag --points-at HEAD)" "$(git -C "$AR_COMPS/$component" rev-parse --short HEAD)"\r\n" + fi + fi + done + pr_body+="tinyusb: "$(git -C "$AR_COMPS/arduino_tinyusb/tinyusb" symbolic-ref --short HEAD || git -C "$AR_COMPS/arduino_tinyusb/tinyusb" tag --points-at HEAD)" "$(git -C "$AR_COMPS/arduino_tinyusb/tinyusb" rev-parse --short HEAD)"\r\n" + local pr_data="{\"title\": \"$pr_title\", \"body\": \"$pr_body\", \"head\": \"$AR_USER:$pr_branch\", \"base\": \"$pr_target\"}" + git_create_pr_res=`echo "$pr_data" | curl -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" --data @- "https://api.github.com/repos/$AR_REPO/pulls"` + local done_pr=`echo "$git_create_pr_res" | jq -r '.title'` + if [ ! "$done_pr" == "" ] && [ ! "$done_pr" == "null" ]; then echo 1; else echo 0; fi } diff --git a/tools/copy-libs.sh b/tools/copy-libs.sh index e132124c3..9cec8e5ab 100755 --- a/tools/copy-libs.sh +++ b/tools/copy-libs.sh @@ -30,9 +30,15 @@ fi if [ -e "$AR_SDK/include" ]; then rm -rf "$AR_SDK/include" fi +if [ -e "$AR_SDK/flags" ]; then + rm -rf "$AR_SDK/flags" +fi if [ -e "$AR_SDK/$MEMCONF" ]; then rm -rf "$AR_SDK/$MEMCONF" fi +if [ -e "$AR_SDK/platformio-build.py" ]; then + rm -rf "$AR_SDK/platformio-build.py" +fi mkdir -p "$AR_SDK" function get_actual_path(){ @@ -95,7 +101,7 @@ for item in "${@:2:${#@}-5}"; do elif [ "$prefix" = "-O" ]; then PIO_CC_FLAGS+="$item " elif [[ "$item" != "-Wall" && "$item" != "-Werror=all" && "$item" != "-Wextra" ]]; then - if [[ "${item:0:23}" != "-mfix-esp32-psram-cache" && "${item:0:18}" != "-fmacro-prefix-map" ]]; then + if [[ "${item:0:23}" != "-mfix-esp32-psram-cache" && "${item:0:18}" != "-fmacro-prefix-map" && "${item:0:20}" != "-fdiagnostics-color=" ]]; then C_FLAGS+="$item " fi fi @@ -109,7 +115,7 @@ set -- $str for item in "${@:2:${#@}-5}"; do prefix="${item:0:2}" if [[ "$prefix" != "-I" && "$prefix" != "-D" && "$item" != "-Wall" && "$item" != "-Werror=all" && "$item" != "-Wextra" && "$prefix" != "-O" ]]; then - if [[ "${item:0:23}" != "-mfix-esp32-psram-cache" && "${item:0:18}" != "-fmacro-prefix-map" ]]; then + if [[ "${item:0:23}" != "-mfix-esp32-psram-cache" && "${item:0:18}" != "-fmacro-prefix-map" && "${item:0:20}" != "-fdiagnostics-color=" ]]; then AS_FLAGS+="$item " if [[ $C_FLAGS == *"$item"* ]]; then PIO_CC_FLAGS+="$item " @@ -128,7 +134,7 @@ set -- $str for item in "${@:2:${#@}-5}"; do prefix="${item:0:2}" if [[ "$prefix" != "-I" && "$prefix" != "-D" && "$item" != "-Wall" && "$item" != "-Werror=all" && "$item" != "-Wextra" && "$prefix" != "-O" ]]; then - if [[ "${item:0:23}" != "-mfix-esp32-psram-cache" && "${item:0:18}" != "-fmacro-prefix-map" ]]; then + if [[ "${item:0:23}" != "-mfix-esp32-psram-cache" && "${item:0:18}" != "-fmacro-prefix-map" && "${item:0:20}" != "-fdiagnostics-color=" ]]; then CPP_FLAGS+="$item " if [[ $PIO_CC_FLAGS != *"$item"* ]]; then PIO_CXX_FLAGS+="$item " @@ -155,13 +161,15 @@ else libs="${libs:19:${#libs}-1}" flags=`cat build/build.ninja | grep LINK_FLAGS` flags="${flags:15:${#flags}-1}" + paths=`cat build/build.ninja | grep LINK_PATH` + paths="${paths:14:${#paths}-1}" if [ "$IDF_TARGET" = "esp32" ]; then flags="-Wno-frame-address $flags" fi - if [ "$IDF_TARGET" != "esp32c3" ]; then + if [ "$IS_XTENSA" = "y" ]; then flags="-mlongcalls $flags" fi - str="$flags $libs" + str="$flags $libs $paths" fi if [ "$IDF_TARGET" = "esp32" ]; then LD_SCRIPTS+="-T esp32.rom.redefined.ld " @@ -271,13 +279,11 @@ done # END OF DATA EXTRACTION FROM CMAKE # -AR_PLATFORMIO_PY="$AR_TOOLS/platformio-build-$IDF_TARGET.py" +mkdir -p "$AR_SDK" # start generation of platformio-build.py -awk "/ASFLAGS=\[/{n++}{print>n\"pio_start.txt\"}" $AR_COMPS/arduino/tools/platformio-build-$IDF_TARGET.py -awk "/\"ARDUINO_ARCH_ESP32\"/{n++}{print>n\"pio_end.txt\"}" 1pio_start.txt -cat pio_start.txt > "$AR_PLATFORMIO_PY" -rm pio_end.txt 1pio_start.txt pio_start.txt +AR_PLATFORMIO_PY="$AR_SDK/platformio-build.py" +cat configs/pio_start.txt > "$AR_PLATFORMIO_PY" echo " ASFLAGS=[" >> "$AR_PLATFORMIO_PY" if [ "$IS_XTENSA" = "y" ]; then @@ -348,8 +354,8 @@ echo " '-Wl,-Map=\"%s\"' % join(\"\${BUILD_DIR}\", \"\${PROGNAME}.map\")" echo " ]," >> "$AR_PLATFORMIO_PY" echo "" >> "$AR_PLATFORMIO_PY" -# # include dirs -AR_INC="" +# include dirs +REL_INC="" echo " CPPPATH=[" >> "$AR_PLATFORMIO_PY" set -- $INCLUDES @@ -376,13 +382,13 @@ for item; do out_sub="${item#*$ipath}" out_cpath="$AR_SDK/include/$fname$out_sub" - AR_INC+=" \"-I{compiler.sdk.path}/include/$fname$out_sub\"" + REL_INC+="-iwithprefixbefore $fname$out_sub " if [ "$out_sub" = "" ]; then - echo " join(FRAMEWORK_DIR, \"tools\", \"sdk\", \"$IDF_TARGET\", \"include\", \"$fname\")," >> "$AR_PLATFORMIO_PY" + echo " join($PIO_SDK, \"include\", \"$fname\")," >> "$AR_PLATFORMIO_PY" else pio_sub="${out_sub:1}" pio_sub=`echo $pio_sub | sed 's/\//\\", \\"/g'` - echo " join(FRAMEWORK_DIR, \"tools\", \"sdk\", \"$IDF_TARGET\", \"include\", \"$fname\", \"$pio_sub\")," >> "$AR_PLATFORMIO_PY" + echo " join($PIO_SDK, \"include\", \"$fname\", \"$pio_sub\")," >> "$AR_PLATFORMIO_PY" fi for f in `find "$item" -name '*.h'`; do rel_f=${f#*$item} @@ -396,10 +402,15 @@ for item; do mkdir -p "$out_cpath$rel_p" cp -n $f "$out_cpath$rel_p/" done + # Temporary measure to fix issues caused by https://github.com/espressif/esp-idf/commit/dc4731101dd567cc74bbe4d0f03afe52b7db9afb#diff-1d2ce0d3989a80830fdf230bcaafb3117f32046d16cf46616ac3d55b4df2a988R17 + if [[ "$fname" == "bt" && "$out_sub" == "/include/$IDF_TARGET/include" && -f "$ipath/controller/$IDF_TARGET/esp_bt_cfg.h" ]]; then + mkdir -p "$AR_SDK/include/$fname/controller/$IDF_TARGET" + cp -n "$ipath/controller/$IDF_TARGET/esp_bt_cfg.h" "$AR_SDK/include/$fname/controller/$IDF_TARGET/esp_bt_cfg.h" + fi fi done -echo " join(FRAMEWORK_DIR, \"tools\", \"sdk\", \"$IDF_TARGET\", env.BoardConfig().get(\"build.arduino.memory_type\", (env.BoardConfig().get(\"build.flash_mode\", \"dio\") + \"_$OCT_PSRAM\")), \"include\")," >> "$AR_PLATFORMIO_PY" -echo " join(FRAMEWORK_DIR, \"cores\", env.BoardConfig().get(\"build.core\"))" >> "$AR_PLATFORMIO_PY" +echo " join($PIO_SDK, board_config.get(\"build.arduino.memory_type\", (board_config.get(\"build.flash_mode\", \"dio\") + \"_$OCT_PSRAM\")), \"include\")," >> "$AR_PLATFORMIO_PY" +echo " join(FRAMEWORK_DIR, \"cores\", board_config.get(\"build.core\"))" >> "$AR_PLATFORMIO_PY" echo " ]," >> "$AR_PLATFORMIO_PY" echo "" >> "$AR_PLATFORMIO_PY" @@ -421,9 +432,9 @@ for item; do done echo " LIBPATH=[" >> "$AR_PLATFORMIO_PY" -echo " join(FRAMEWORK_DIR, \"tools\", \"sdk\", \"$IDF_TARGET\", \"lib\")," >> "$AR_PLATFORMIO_PY" -echo " join(FRAMEWORK_DIR, \"tools\", \"sdk\", \"$IDF_TARGET\", \"ld\")," >> "$AR_PLATFORMIO_PY" -echo " join(FRAMEWORK_DIR, \"tools\", \"sdk\", \"$IDF_TARGET\", env.BoardConfig().get(\"build.arduino.memory_type\", (env.BoardConfig().get(\"build.flash_mode\", \"dio\") + \"_$OCT_PSRAM\")))" >> "$AR_PLATFORMIO_PY" +echo " join($PIO_SDK, \"lib\")," >> "$AR_PLATFORMIO_PY" +echo " join($PIO_SDK, \"ld\")," >> "$AR_PLATFORMIO_PY" +echo " join($PIO_SDK, board_config.get(\"build.arduino.memory_type\", (board_config.get(\"build.flash_mode\", \"dio\") + \"_$OCT_PSRAM\")))" >> "$AR_PLATFORMIO_PY" echo " ]," >> "$AR_PLATFORMIO_PY" echo "" >> "$AR_PLATFORMIO_PY" @@ -449,40 +460,36 @@ for item; do fi done -# remove backslashes for Arduino -DEFINES=`echo "$DEFINES" | tr -d '\\'` - - # end generation of platformio-build.py -cat 1pio_end.txt >> "$AR_PLATFORMIO_PY" -rm 1pio_end.txt - -# arduino platform.txt -platform_file="$AR_COMPS/arduino/platform.txt" -if [ -f "$AR_PLATFORM_TXT" ]; then - # use the file we have already compiled for other chips - platform_file="$AR_PLATFORM_TXT" +cat configs/pio_end.txt >> "$AR_PLATFORMIO_PY" + +# replace double backslashes with single one +DEFINES=`echo "$DEFINES" | tr -s '\'` + +# target flags files +FLAGS_DIR="$AR_SDK/flags" +mkdir -p "$FLAGS_DIR" +echo -n "$DEFINES" > "$FLAGS_DIR/defines" +echo -n "$REL_INC" > "$FLAGS_DIR/includes" +echo -n "$C_FLAGS" > "$FLAGS_DIR/c_flags" +echo -n "$CPP_FLAGS" > "$FLAGS_DIR/cpp_flags" +echo -n "$AS_FLAGS" > "$FLAGS_DIR/S_flags" +echo -n "$LD_FLAGS" > "$FLAGS_DIR/ld_flags" +echo -n "$LD_SCRIPTS" > "$FLAGS_DIR/ld_scripts" +echo -n "$AR_LIBS" > "$FLAGS_DIR/ld_libs" + +# sr model.bin +if [ -f "build/srmodels/srmodels.bin" ]; then + mkdir -p "$AR_SDK/esp_sr" + cp -f "build/srmodels/srmodels.bin" "$AR_SDK/esp_sr/" + cp -f "partitions.csv" "$AR_SDK/esp_sr/" fi -awk "/compiler.cpreprocessor.flags.$IDF_TARGET=/{n++}{print>n\"platform_start.txt\"}" "$platform_file" -$SED -i "/compiler.cpreprocessor.flags.$IDF_TARGET\=/d" 1platform_start.txt -awk "/compiler.ar.flags.$IDF_TARGET=/{n++}{print>n\"platform_mid.txt\"}" 1platform_start.txt -rm -rf 1platform_start.txt - -cat platform_start.txt > "$AR_PLATFORM_TXT" -echo "compiler.cpreprocessor.flags.$IDF_TARGET=$DEFINES $AR_INC" >> "$AR_PLATFORM_TXT" -echo "compiler.c.elf.libs.$IDF_TARGET=$AR_LIBS" >> "$AR_PLATFORM_TXT" -echo "compiler.c.flags.$IDF_TARGET=$C_FLAGS -MMD -c" >> "$AR_PLATFORM_TXT" -echo "compiler.cpp.flags.$IDF_TARGET=$CPP_FLAGS -MMD -c" >> "$AR_PLATFORM_TXT" -echo "compiler.S.flags.$IDF_TARGET=$AS_FLAGS -x assembler-with-cpp -MMD -c" >> "$AR_PLATFORM_TXT" -echo "compiler.c.elf.flags.$IDF_TARGET=$LD_SCRIPTS $LD_FLAGS" >> "$AR_PLATFORM_TXT" -cat 1platform_mid.txt >> "$AR_PLATFORM_TXT" -rm -rf platform_start.txt platform_mid.txt 1platform_mid.txt # sdkconfig cp -f "sdkconfig" "$AR_SDK/sdkconfig" # gen_esp32part.py -cp "$IDF_COMPS/partition_table/gen_esp32part.py" "$AR_GEN_PART_PY" +# cp "$IDF_PATH/components/partition_table/gen_esp32part.py" "$AR_GEN_PART_PY" # copy precompiled libs (if we need them) function copy_precompiled_lib(){ diff --git a/tools/copy-to-arduino.sh b/tools/copy-to-arduino.sh index ef8b9074c..96092e068 100755 --- a/tools/copy-to-arduino.sh +++ b/tools/copy-to-arduino.sh @@ -16,10 +16,8 @@ fi echo "Installing new libraries to $ESP32_ARDUINO" -rm -rf $ESP32_ARDUINO/tools/sdk $ESP32_ARDUINO/tools/gen_esp32part.py $ESP32_ARDUINO/tools/platformio-build-*.py $ESP32_ARDUINO/platform.txt - -cp -f $AR_OUT/platform.txt $ESP32_ARDUINO/ +rm -rf $ESP32_ARDUINO/package/package_esp32_index.template.json && \ cp -f $AR_OUT/package_esp32_index.template.json $ESP32_ARDUINO/package/package_esp32_index.template.json -cp -Rf $AR_TOOLS/sdk $ESP32_ARDUINO/tools/ -cp -f $AR_TOOLS/gen_esp32part.py $ESP32_ARDUINO/tools/ -cp -f $AR_TOOLS/platformio-build-*.py $ESP32_ARDUINO/tools/ + +rm -rf $ESP32_ARDUINO/tools/esp32-arduino-libs && \ +cp -Rf $AR_TOOLS/esp32-arduino-libs $ESP32_ARDUINO/tools/ diff --git a/tools/cron.sh b/tools/cron.sh old mode 100644 new mode 100755 index 2a3fb88cd..000fdc4dc --- a/tools/cron.sh +++ b/tools/cron.sh @@ -5,7 +5,4 @@ if [ ! "$GITHUB_EVENT_NAME" == "schedule" ]; then exit 1 fi -git checkout "$IDF_BRANCH" #local branches should match what the matrix wants to build -DEPLOY_OUT=1 -source ./build.sh -# bash ./tools/push-to-arduino.sh +bash ./build.sh -d diff --git a/tools/gen_platformio_manifest.py b/tools/gen_platformio_manifest.py new file mode 100644 index 000000000..2d031b687 --- /dev/null +++ b/tools/gen_platformio_manifest.py @@ -0,0 +1,86 @@ +import argparse +import json +import os +import re +import sys + +MANIFEST_DATA = { + "name": "framework-arduinoespressif32-libs", + "description": "Precompiled libraries for Arduino Wiring-based Framework for the Espressif ESP32 series of SoCs", + "keywords": ["framework", "arduino", "espressif", "esp32"], + "license": "LGPL-2.1-or-later", + "repository": { + "type": "git", + "url": "https://github.com/espressif/esp32-arduino-libs", + }, +} + + +def convert_version(version_string): + """A helper function that converts a custom IDF version string + extracted from a Git repository to a suitable SemVer alternative. For example: + 'release/v5.1' becomes '5.1.0', + 'v7.7.7' becomes '7.7.7' + """ + + regex_pattern = ( + r"v(?P<MAJOR>0|[1-9]\d*)\.(?P<MINOR>0|[1-9]\d*)\.*(?P<PATCH>0|[1-9]\d*)*" + ) + match = re.search(regex_pattern, version_string) + if not match: + sys.stderr.write( + f"Failed to find a regex match for '{regex_pattern}' in '{version_string}'\n" + ) + return "" + + major, minor, patch = match.groups() + if not patch: + patch = "0" + + return ".".join((major, minor, patch)) + + +def main(dst_dir, version_string, commit_hash): + + converted_version = convert_version(version_string) + if not converted_version: + sys.stderr.write(f"Failed to convert version '{version_string}'\n") + return -1 + + manifest_file_path = os.path.join(dst_dir, "package.json") + with open(manifest_file_path, "w", encoding="utf8") as fp: + MANIFEST_DATA["version"] = f"{converted_version}+sha.{commit_hash}" + json.dump(MANIFEST_DATA, fp, indent=2) + + print( + f"Generated PlatformIO manifest file '{manifest_file_path}' with '{converted_version}' version" + ) + return 0 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-o", + "--dst-dir", + dest="dst_dir", + required=True, + help="Destination folder where the 'package.json' manifest will be located", + ) + parser.add_argument( + "-s", + "--version-string", + dest="version_string", + required=True, + help="ESP-IDF version string used for compiling libraries", + ) + parser.add_argument( + "-c", + "--commit-hash", + dest="commit_hash", + required=True, + help="ESP-IDF revision in form of a commit hash", + ) + args = parser.parse_args() + + sys.exit(main(args.dst_dir, args.version_string, args.commit_hash)) diff --git a/tools/gen_tools_json.py b/tools/gen_tools_json.py index c63d1e962..ca53ec8cb 100644 --- a/tools/gen_tools_json.py +++ b/tools/gen_tools_json.py @@ -25,10 +25,17 @@ prog = 'gen_tools_json', description = 'Update Arduino package index with the tolls found in ESP-IDF') parser.add_argument('-i', '--esp-idf', dest='idf_path', required=True, help='Path to ESP-IDF') - parser.add_argument('-j', '--pkg-json', dest='arduino_json', required=True, help='path to Arduino package json') + parser.add_argument('-j', '--pkg-json', dest='arduino_json', required=False, help='path to Arduino package json') parser.add_argument('-o', '--out-path', dest='out_path', required=True, help='Output path to store the update package json') args = parser.parse_args() + simple_output = False + if args.arduino_json == None: + print('Source was not selected') + simple_output = True + else: + print('Source {0}.'.format(args.arduino_json)) + idf_path = args.idf_path; arduino_json = args.arduino_json; out_path = args.out_path; @@ -37,7 +44,9 @@ arduino_tools = ["xtensa-esp32-elf","xtensa-esp32s2-elf","xtensa-esp32s3-elf","xtensa-esp-elf-gdb","riscv32-esp-elf","riscv32-esp-elf-gdb","openocd-esp32"] # code start - farray = json.load(open(arduino_json)) + farray = {"packages":[{"platforms":[{"toolsDependencies":[]}],"tools":[]}]} + if simple_output == False: + farray = json.load(open(arduino_json)) idf_tools = json.load(open(idf_path + '/tools/tools.json')) for tool in idf_tools['tools']: @@ -51,21 +60,30 @@ tool_name += '-gcc' print('Found {0}, version: {1}'.format(tool_name, tool_version)) - dep_found = False - dep_skip = False - for dep in farray['packages'][0]['platforms'][0]['toolsDependencies']: - if dep['name'] == tool_name: - if dep['version'] == tool_version: - print('Skipping {0}. Same version {1}'.format(tool_name, tool_version)) - dep_skip = True - break - print('Updating dependency version of {0} from {1} to {2}'.format(tool_name, dep['version'], tool_version)) - dep['version'] = tool_version - dep_found = True - if dep_skip == True: - continue - if dep_found == False: - print('Adding new dependency: {0} version {1}'.format(tool_name, tool_version)) + if simple_output == False: + dep_found = False + dep_skip = False + for dep in farray['packages'][0]['platforms'][0]['toolsDependencies']: + if dep['name'] == tool_name: + if dep['version'] == tool_version: + print('Skipping {0}. Same version {1}'.format(tool_name, tool_version)) + dep_skip = True + break + print('Updating dependency version of {0} from {1} to {2}'.format(tool_name, dep['version'], tool_version)) + dep['version'] = tool_version + dep_found = True + if dep_skip == True: + continue + if dep_found == False: + print('Adding new dependency: {0} version {1}'.format(tool_name, tool_version)) + deps = { + "packager": "esp32", + "name": tool_name, + "version": tool_version + } + farray['packages'][0]['platforms'][0]['toolsDependencies'].append(deps) + else: + print('Adding dependency: {0} version {1}'.format(tool_name, tool_version)) deps = { "packager": "esp32", "name": tool_name, @@ -84,7 +102,7 @@ "url": tool_data['url'], "archiveFileName": os.path.basename(tool_data['url']), "checksum": "SHA-256:"+tool_data['sha256'], - "size": tool_data['size'] + "size": str(tool_data['size']) } if arch == "win32": @@ -111,15 +129,24 @@ systems.append(system) - tool_found = False - for t in farray['packages'][0]['tools']: - if t['name'] == tool_name: - t['version'] = tool_version - t['systems'] = systems - tool_found = True - print('Updating binaries of {0} to version {1}'.format(tool_name, tool_version)) - if tool_found == False: - print('Adding new tool: {0} version {1}'.format(tool_name, tool_version)) + if simple_output == False: + tool_found = False + for t in farray['packages'][0]['tools']: + if t['name'] == tool_name: + t['version'] = tool_version + t['systems'] = systems + tool_found = True + print('Updating binaries of {0} to version {1}'.format(tool_name, tool_version)) + if tool_found == False: + print('Adding new tool: {0} version {1}'.format(tool_name, tool_version)) + tools = { + "name": tool_name, + "version": tool_version, + "systems": systems + } + farray['packages'][0]['tools'].append(tools) + else: + print('Adding tool: {0} version {1}'.format(tool_name, tool_version)) tools = { "name": tool_name, "version": tool_version, @@ -128,7 +155,10 @@ farray['packages'][0]['tools'].append(tools) json_str = json.dumps(farray, indent=2) - out_file = out_path + os.path.basename(arduino_json) + out_file = out_path + "tools.json" + if simple_output == False: + out_file = out_path + os.path.basename(arduino_json) + with open(out_file, "w") as f: f.write(json_str+"\n") f.close() diff --git a/tools/get_projbuild_gitconfig.py b/tools/get_projbuild_gitconfig.py new file mode 100644 index 000000000..305bb117c --- /dev/null +++ b/tools/get_projbuild_gitconfig.py @@ -0,0 +1,124 @@ +# This file is expected to be present in ${COMPONENT_DIR} +# accessed from components/esp_insights/CMakeLists.txt +# Used in: +# 1. Project ESP Insights build package tar file + +#from __future__ import unicode_literals +import os +import sys +import json +import subprocess +from builtins import range, str +from io import open + +# Input project directory from CMakeLists.txt +PROJ_DIR=sys.argv[1] +# Input project name +PROJ_NAME=sys.argv[2] +# Input project version +PROJ_VER=sys.argv[3] +# Input custom config filename from CMakeLists.txt +FILENAME=sys.argv[4] +# Input IDF_PATH from CMakeLists.txt +IDF_PATH=sys.argv[5] +# Input target +TARGET=sys.argv[6] + +NEWLINE = "\n" + +CONFIG = {} + +# Set Config + +# Set current directory i.e Set ${COMPONENT_DIR} as current directory +CURR_DIR = os.getcwd() + +def _change_dir(dirname): + # Change directory + os.chdir(dirname) + + +def _set_submodule_cfg(submodules, repo_name): + # Set config for submodules + CFG_TITLE = "submodules" + NAME_STR = "name" + VERSION_STR = "version" + CONFIG[repo_name][CFG_TITLE] = [] + + if submodules: + # Get the submodule name and version + submodules_list = submodules.strip().split(NEWLINE) + for i in range(0, len(submodules_list), 2): + name = submodules_list[i].split('\'')[1] + version = submodules_list[i+1] + submodule_json = { NAME_STR: name, VERSION_STR: version } + CONFIG[repo_name][CFG_TITLE].append(submodule_json) + + +def run_cmd(command, get_basename=False): + try: + resp = subprocess.check_output(command, shell=True).strip().decode('utf-8') + if get_basename: + resp = os.path.basename(resp) + return resp + except subprocess.CalledProcessError: + raise Exception("ERROR: Please check command : {}".format(command)) + +def set_cfg(config_name): + # Set config for ESP-IDF Repo + if config_name == "esp-idf": + # Get repo name (for IDF repo) + REPO_CMD='git rev-parse --show-toplevel' + repo_name = run_cmd(REPO_CMD, get_basename=True) + CONFIG[repo_name] = {} + + # Get commit HEAD + GITHEAD_STR = "HEAD" + HEAD='git describe --always --tags --dirty' + head_ver = run_cmd(HEAD) + CONFIG[repo_name][GITHEAD_STR] = head_ver + + # Get submodule latest refs + SUBMODULE = 'git submodule foreach git describe --always --tags --dirty' + submodules = run_cmd(SUBMODULE) + _set_submodule_cfg(submodules, repo_name) + elif config_name == "toolchain": + # Set config for Toolchain Version + arch_target = "xtensa-" + TARGET + if TARGET == "esp32c3" or TARGET == "esp32c2" or TARGET == "esp32h2" or TARGET == "esp32c6": + arch_target = "riscv32-esp" + # Get toolchain version + TOOLCHAIN_STR = "toolchain" + TOOLCHAIN = arch_target + '-elf-gcc --version' + toolchain = run_cmd(TOOLCHAIN) + CONFIG[TOOLCHAIN_STR] = toolchain.strip().split(NEWLINE)[0] + +# Set project details - name and version +def set_project_details(): + # Set project name and version + CONFIG['project'] = {} + CONFIG['project']['name'] = PROJ_NAME + CONFIG['project']['version'] = PROJ_VER + +try: + with open(FILENAME, "w+", encoding="utf-8") as output_file: + # ESP-IDF REPO CONFIG + # Change to ESP-IDF Directory + _change_dir(IDF_PATH) + set_cfg("esp-idf") + + # Change back to ${COMPONENT_DIR} + _change_dir(CURR_DIR) + + # Set project name and version + set_project_details() + + # GET TOOLCHAIN VERSION + set_cfg("toolchain") + + output_file.write(str(json.dumps(CONFIG, indent=4, sort_keys=True))) + +except Exception as e: + # Remove config file created if error occurs + os.system("rm " + FILENAME) + sys.exit(e) \ No newline at end of file diff --git a/tools/install-arduino.sh b/tools/install-arduino.sh new file mode 100755 index 000000000..51e1162a4 --- /dev/null +++ b/tools/install-arduino.sh @@ -0,0 +1,62 @@ +#/bin/bash + +source ./tools/config.sh + +# +# CLONE/UPDATE ARDUINO +# +echo "Updating ESP32 Arduino..." +if [ ! -d "$AR_COMPS/arduino" ]; then + git clone $AR_REPO_URL "$AR_COMPS/arduino" +fi + +if [ -z $AR_BRANCH ]; then + if [ -z $GITHUB_HEAD_REF ]; then + current_branch=`git branch --show-current` + else + current_branch="$GITHUB_HEAD_REF" + fi + echo "Current Branch: $current_branch" + if [[ "$current_branch" != "master" && `git_branch_exists "$AR_COMPS/arduino" "$current_branch"` == "1" ]]; then + export AR_BRANCH="$current_branch" + else + if [ "$IDF_TAG" ]; then #tag was specified at build time + AR_BRANCH_NAME="idf-$IDF_TAG" + elif [ "$IDF_COMMIT" ]; then #commit was specified at build time + AR_BRANCH_NAME="idf-$IDF_COMMIT" + else + AR_BRANCH_NAME="idf-$IDF_BRANCH" + fi + has_ar_branch=`git_branch_exists "$AR_COMPS/arduino" "$AR_BRANCH_NAME"` + if [ "$has_ar_branch" == "1" ]; then + export AR_BRANCH="$AR_BRANCH_NAME" + else + has_ar_branch=`git_branch_exists "$AR_COMPS/arduino" "$AR_PR_TARGET_BRANCH"` + if [ "$has_ar_branch" == "1" ]; then + export AR_BRANCH="$AR_PR_TARGET_BRANCH" + fi + fi + fi +fi + +if [ "$AR_BRANCH" ]; then + echo "AR_BRANCH='$AR_BRANCH'" + git -C "$AR_COMPS/arduino" checkout "$AR_BRANCH" && \ + git -C "$AR_COMPS/arduino" fetch && \ + git -C "$AR_COMPS/arduino" pull --ff-only +fi +if [ $? -ne 0 ]; then exit 1; fi + +# +# CLONE/UPDATE ESP32-ARDUINO-LIBS +# +if [ ! -d "$IDF_LIBS_DIR" ]; then + echo "Cloning esp32-arduino-libs..." + git clone "$AR_LIBS_REPO_URL" "$IDF_LIBS_DIR" +else + echo "Updating esp32-arduino-libs..." + git -C "$IDF_LIBS_DIR" fetch && \ + git -C "$IDF_LIBS_DIR" pull --ff-only +fi +if [ $? -ne 0 ]; then exit 1; fi + diff --git a/tools/install-esp-idf.sh b/tools/install-esp-idf.sh index 2b7a0f5fb..90f27fd0a 100755 --- a/tools/install-esp-idf.sh +++ b/tools/install-esp-idf.sh @@ -11,14 +11,16 @@ fi # CLONE ESP-IDF # -IDF_REPO_URL="https://github.com/espressif/esp-idf.git" if [ ! -d "$IDF_PATH" ]; then echo "ESP-IDF is not installed! Installing local copy" git clone $IDF_REPO_URL -b $IDF_BRANCH idf_was_installed="1" fi -if [ "$IDF_COMMIT" ]; then +if [ "$IDF_TAG" ]; then + git -C "$IDF_PATH" checkout "tags/$IDF_TAG" + idf_was_installed="1" +elif [ "$IDF_COMMIT" ]; then git -C "$IDF_PATH" checkout "$IDF_COMMIT" commit_predefined="1" fi @@ -30,6 +32,13 @@ fi if [ ! -x $idf_was_installed ] || [ ! -x $commit_predefined ]; then git -C $IDF_PATH submodule update --init --recursive $IDF_PATH/install.sh + export IDF_COMMIT=$(git -C "$IDF_PATH" rev-parse --short HEAD) + export IDF_BRANCH=$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD) + + # Temporarily patch the ETH driver to support custom SPI + cd $IDF_PATH + patch -p1 -i ../patches/spi_eth.diff + cd - fi # @@ -37,8 +46,6 @@ fi # source $IDF_PATH/export.sh -export IDF_COMMIT=$(git -C "$IDF_PATH" rev-parse --short HEAD) -export IDF_BRANCH=$(git -C "$IDF_PATH" symbolic-ref --short HEAD || git -C "$IDF_PATH" tag --points-at HEAD) # # SETUP ARDUINO DEPLOY @@ -55,41 +62,25 @@ if [ "$GITHUB_EVENT_NAME" == "schedule" ] || [ "$GITHUB_EVENT_NAME" == "reposito AR_NEW_COMMIT_MESSAGE="IDF $IDF_COMMIT" AR_NEW_PR_TITLE="$AR_NEW_COMMIT_MESSAGE" fi + LIBS_VERSION="idf-"${IDF_BRANCH//\//_}"-$IDF_COMMIT" AR_HAS_COMMIT=`git_commit_exists "$AR_COMPS/arduino" "$AR_NEW_COMMIT_MESSAGE"` AR_HAS_BRANCH=`git_branch_exists "$AR_COMPS/arduino" "$AR_NEW_BRANCH_NAME"` - AR_HAS_PR=`git_pr_exists "$AR_NEW_BRANCH_NAME"` + AR_HAS_PR=`github_pr_exists "$AR_REPO" "$AR_NEW_BRANCH_NAME"` - if [ "$AR_HAS_COMMIT" == "1" ]; then - echo "Commit '$AR_NEW_COMMIT_MESSAGE' Already Exists" - mkdir -p dist && echo "Commit '$AR_NEW_COMMIT_MESSAGE' Already Exists" > dist/log.txt - exit 0 - fi + LIBS_HAS_COMMIT=`git_commit_exists "$IDF_LIBS_DIR" "$AR_NEW_COMMIT_MESSAGE"` + LIBS_HAS_BRANCH=`git_branch_exists "$IDF_LIBS_DIR" "$AR_NEW_BRANCH_NAME"` - if [ "$AR_HAS_BRANCH" == "1" ]; then - echo "Branch '$AR_NEW_BRANCH_NAME' Already Exists" + if [ "$LIBS_HAS_COMMIT" == "1" ]; then + echo "Commit '$AR_NEW_COMMIT_MESSAGE' Already Exists in esp32-arduino-libs" fi - if [ "$AR_HAS_PR" == "1" ]; then - echo "PR '$AR_NEW_PR_TITLE' Already Exists" + if [ "$AR_HAS_COMMIT" == "1" ]; then + echo "Commit '$AR_NEW_COMMIT_MESSAGE' Already Exists in arduino-esp32" fi - # setup git for pushing - git config --global github.user "$GITHUB_ACTOR" - git config --global user.name "$GITHUB_ACTOR" - git config --global user.email "$GITHUB_ACTOR@github.com" - - # create or checkout the branch - if [ ! $AR_HAS_BRANCH == "0" ]; then - echo "Switching to arduino branch '$AR_NEW_BRANCH_NAME'..." - git -C "$AR_COMPS/arduino" checkout $AR_NEW_BRANCH_NAME - else - echo "Creating arduino branch '$AR_NEW_BRANCH_NAME'..." - git -C "$AR_COMPS/arduino" checkout -b $AR_NEW_BRANCH_NAME - fi - if [ $? -ne 0 ]; then - echo "ERROR: Checkout of branch '$AR_NEW_BRANCH_NAME' failed" - exit 1 + if [ "$LIBS_HAS_COMMIT" == "1" ] && [ "$AR_HAS_COMMIT" == "1" ]; then + exit 0 fi export AR_NEW_BRANCH_NAME @@ -99,4 +90,8 @@ if [ "$GITHUB_EVENT_NAME" == "schedule" ] || [ "$GITHUB_EVENT_NAME" == "reposito export AR_HAS_COMMIT export AR_HAS_BRANCH export AR_HAS_PR + + export LIBS_VERSION + export LIBS_HAS_COMMIT + export LIBS_HAS_BRANCH fi diff --git a/tools/push-to-arduino.sh b/tools/push-to-arduino.sh index f9a2b9955..f4d794d0c 100755 --- a/tools/push-to-arduino.sh +++ b/tools/push-to-arduino.sh @@ -11,14 +11,117 @@ if ! [ -d "$AR_COMPS/arduino" ]; then exit 1 fi +# setup git for pushing +git config --global github.user "$GITHUB_ACTOR" +git config --global user.name "$GITHUB_ACTOR" +git config --global user.email "$GITHUB_ACTOR@github.com" + # # UPDATE FILES # +# +# esp32-arduino-libs +# + +if [ $LIBS_HAS_COMMIT == "0" ] || [ $AR_HAS_COMMIT == "0" ]; then + cd "$AR_ROOT" + # create branch if necessary + if [ "$LIBS_HAS_BRANCH" == "1" ]; then + echo "Branch '$AR_NEW_BRANCH_NAME' Already Exists" + echo "Switching to esp32-arduino-libs branch '$AR_NEW_BRANCH_NAME'..." + git -C "$IDF_LIBS_DIR" checkout $AR_NEW_BRANCH_NAME + else + echo "Creating esp32-arduino-libs branch '$AR_NEW_BRANCH_NAME'..." + git -C "$IDF_LIBS_DIR" checkout -b $AR_NEW_BRANCH_NAME + fi + if [ $? -ne 0 ]; then + echo "ERROR: Checkout of branch '$AR_NEW_BRANCH_NAME' failed" + exit 1 + fi + + # make changes to the files + echo "Patching files in esp32-arduino-libs branch '$AR_NEW_BRANCH_NAME'..." + rm -rf $IDF_LIBS_DIR/* && cp -Rf $AR_TOOLS/esp32-arduino-libs/* $IDF_LIBS_DIR/ + + cd $IDF_LIBS_DIR + if [ -f "README.md" ]; then + rm -rf "README.md" + fi + + # did any of the files change? + if [ -n "$(git status --porcelain)" ]; then + echo "Pushing changes to esp32-arduino-libs branch '$AR_NEW_BRANCH_NAME'..." + git add . && git commit --message "$AR_NEW_COMMIT_MESSAGE" && git push -u origin $AR_NEW_BRANCH_NAME + if [ $? -ne 0 ]; then + echo "ERROR: Pushing to branch '$AR_NEW_BRANCH_NAME' failed" + exit 1 + fi + IDF_LIBS_COMMIT=`git rev-parse --verify HEAD` + IDF_LIBS_DL_URL="https://codeload.github.com/espressif/esp32-arduino-libs/zip/$IDF_LIBS_COMMIT" + # ToDo: this URL needs to get into Arduino's package.json + + # Download the file + filename="esp32-arduino-libs-$IDF_LIBS_COMMIT.zip" + curl -s -o "$filename" "$IDF_LIBS_DL_URL" + + # Check if the download was successful + if [ $? -ne 0 ]; then + echo "Error downloading file from $IDF_LIBS_DL_URL" + exit 1 + fi + + # Calculate the size in bytes and SHA-256 sum + size=$(stat -c%s "$filename") + sha256sum=$(sha256sum "$filename" | awk '{print $1}') + + # Clean up the downloaded file + rm "$filename" + + # Print the results + echo "Tool: esp32-arduino-libs" + echo "Version: $LIBS_VERSION" + echo "URL: $IDF_LIBS_DL_URL" + echo "File: $filename" + echo "Size: $size bytes" + echo "SHA-256: $sha256sum" + echo "JSON: $AR_OUT/package_esp32_index.template.json" + cd "$AR_ROOT" + python3 tools/add_sdk_json.py -j "$AR_OUT/package_esp32_index.template.json" -n "esp32-arduino-libs" -v "$LIBS_VERSION" -u "$IDF_LIBS_DL_URL" -f "$filename" -s "$size" -c "$sha256sum" + if [ $? -ne 0 ]; then exit 1; fi + + else + echo "No changes in esp32-arduino-libs branch '$AR_NEW_BRANCH_NAME'" + if [ $LIBS_HAS_BRANCH == "0" ]; then + echo "Delete created branch '$AR_NEW_BRANCH_NAME'" + git branch -d $AR_NEW_BRANCH_NAME + fi + exit 0 + fi +fi + +# +# esp32-arduino +# + if [ $AR_HAS_COMMIT == "0" ]; then + cd "$AR_ROOT" + # create or checkout the branch + if [ ! $AR_HAS_BRANCH == "0" ]; then + echo "Switching to arduino branch '$AR_NEW_BRANCH_NAME'..." + git -C "$AR_COMPS/arduino" checkout $AR_NEW_BRANCH_NAME + else + echo "Creating arduino branch '$AR_NEW_BRANCH_NAME'..." + git -C "$AR_COMPS/arduino" checkout -b $AR_NEW_BRANCH_NAME + fi + if [ $? -ne 0 ]; then + echo "ERROR: Checkout of branch '$AR_NEW_BRANCH_NAME' failed" + exit 1 + fi + # make changes to the files echo "Patching files in branch '$AR_NEW_BRANCH_NAME'..." - ESP32_ARDUINO="$AR_COMPS/arduino" ./tools/copy-to-arduino.sh + rm -rf "$AR_COMPS/arduino/package/package_esp32_index.template.json" && cp -f "$AR_OUT/package_esp32_index.template.json" "$AR_COMPS/arduino/package/package_esp32_index.template.json" cd $AR_COMPS/arduino @@ -38,17 +141,18 @@ if [ $AR_HAS_COMMIT == "0" ]; then fi exit 0 fi -fi -# -# CREATE PULL REQUEST -# - -if [ "$AR_HAS_PR" == "0" ]; then - pr_created=`git_create_pr "$AR_NEW_BRANCH_NAME" "$AR_NEW_PR_TITLE" "$AR_PR_TARGET_BRANCH"` - if [ $pr_created == "0" ]; then - echo "ERROR: Failed to create PR '$AR_NEW_PR_TITLE': "`echo "$git_create_pr_res" | jq -r '.message'`": "`echo "$git_create_pr_res" | jq -r '.errors[].message'` - exit 1 + # CREATE PULL REQUEST + if [ "$AR_HAS_PR" == "0" ]; then + echo "Creating PR '$AR_NEW_PR_TITLE'..." + pr_created=`git_create_pr "$AR_NEW_BRANCH_NAME" "$AR_NEW_PR_TITLE" "$AR_PR_TARGET_BRANCH"` + if [ $pr_created == "0" ]; then + echo "ERROR: Failed to create PR '$AR_NEW_PR_TITLE': "`echo "$git_create_pr_res" | jq -r '.message'`": "`echo "$git_create_pr_res" | jq -r '.errors[].message'` + exit 1 + fi + else + echo "PR '$AR_NEW_PR_TITLE' Already Exists" fi fi + exit 0 diff --git a/tools/repository_dispatch.sh b/tools/repository_dispatch.sh old mode 100644 new mode 100755 diff --git a/tools/update-components.sh b/tools/update-components.sh index c00b2853a..13bdd183f 100755 --- a/tools/update-components.sh +++ b/tools/update-components.sh @@ -6,52 +6,9 @@ CAMERA_REPO_URL="https://github.com/espressif/esp32-camera.git" DL_REPO_URL="https://github.com/espressif/esp-dl.git" SR_REPO_URL="https://github.com/espressif/esp-sr.git" RMAKER_REPO_URL="https://github.com/espressif/esp-rainmaker.git" -INSIGHTS_REPO_URL="https://github.com/espressif/esp-insights.git" -DSP_REPO_URL="https://github.com/espressif/esp-dsp.git" LITTLEFS_REPO_URL="https://github.com/joltwallet/esp_littlefs.git" TINYUSB_REPO_URL="https://github.com/hathach/tinyusb.git" - -# -# CLONE/UPDATE ARDUINO -# -echo "Updating ESP32 Arduino..." -if [ ! -d "$AR_COMPS/arduino" ]; then - git clone $AR_REPO_URL "$AR_COMPS/arduino" -fi - -if [ -z $AR_BRANCH ]; then - if [ -z $GITHUB_HEAD_REF ]; then - current_branch=`git branch --show-current` - else - current_branch="$GITHUB_HEAD_REF" - fi - echo "Current Branch: $current_branch" - if [[ "$current_branch" != "master" && `git_branch_exists "$AR_COMPS/arduino" "$current_branch"` == "1" ]]; then - export AR_BRANCH="$current_branch" - else - if [ -z "$IDF_COMMIT" ]; then #commit was not specified at build time - AR_BRANCH_NAME="idf-$IDF_BRANCH" - else - AR_BRANCH_NAME="idf-$IDF_COMMIT" - fi - has_ar_branch=`git_branch_exists "$AR_COMPS/arduino" "$AR_BRANCH_NAME"` - if [ "$has_ar_branch" == "1" ]; then - export AR_BRANCH="$AR_BRANCH_NAME" - else - has_ar_branch=`git_branch_exists "$AR_COMPS/arduino" "$AR_PR_TARGET_BRANCH"` - if [ "$has_ar_branch" == "1" ]; then - export AR_BRANCH="$AR_PR_TARGET_BRANCH" - fi - fi - fi -fi - -if [ "$AR_BRANCH" ]; then - git -C "$AR_COMPS/arduino" checkout "$AR_BRANCH" && \ - git -C "$AR_COMPS/arduino" fetch && \ - git -C "$AR_COMPS/arduino" pull --ff-only -fi -if [ $? -ne 0 ]; then exit 1; fi +TFLITE_REPO_URL="https://github.com/espressif/tflite-micro-esp-examples.git" # # CLONE/UPDATE ESP32-CAMERA @@ -63,10 +20,6 @@ else git -C "$AR_COMPS/esp32-camera" fetch && \ git -C "$AR_COMPS/esp32-camera" pull --ff-only fi -#this is a temp measure to fix build issue -# if [ -f "$AR_COMPS/esp32-camera/idf_component.yml" ]; then -# rm -rf "$AR_COMPS/esp32-camera/idf_component.yml" -# fi if [ $? -ne 0 ]; then exit 1; fi # @@ -75,11 +28,22 @@ if [ $? -ne 0 ]; then exit 1; fi echo "Updating ESP-DL..." if [ ! -d "$AR_COMPS/esp-dl" ]; then git clone $DL_REPO_URL "$AR_COMPS/esp-dl" + #this is a temp measure to fix build issue + mv "$AR_COMPS/esp-dl/CMakeLists.txt" "$AR_COMPS/esp-dl/CMakeListsOld.txt" + echo "idf_build_get_property(target IDF_TARGET)" > "$AR_COMPS/esp-dl/CMakeLists.txt" + echo "if(NOT \${IDF_TARGET} STREQUAL \"esp32c6\" AND NOT \${IDF_TARGET} STREQUAL \"esp32h2\")" >> "$AR_COMPS/esp-dl/CMakeLists.txt" + cat "$AR_COMPS/esp-dl/CMakeListsOld.txt" >> "$AR_COMPS/esp-dl/CMakeLists.txt" + echo "endif()" >> "$AR_COMPS/esp-dl/CMakeLists.txt" + rm -rf "$AR_COMPS/esp-dl/CMakeListsOld.txt" else git -C "$AR_COMPS/esp-dl" fetch && \ git -C "$AR_COMPS/esp-dl" pull --ff-only fi if [ $? -ne 0 ]; then exit 1; fi +#this is a temp measure to fix build issue +if [ -f "$AR_COMPS/esp-dl/idf_component.yml" ]; then + rm -rf "$AR_COMPS/esp-dl/idf_component.yml" +fi # # CLONE/UPDATE ESP-SR @@ -91,24 +55,6 @@ else git -C "$AR_COMPS/esp-sr" fetch && \ git -C "$AR_COMPS/esp-sr" pull --ff-only fi -#this is a temp measure to fix build issue -if [ -f "$AR_COMPS/esp-sr/idf_component.yml" ]; then - rm -rf "$AR_COMPS/esp-sr/idf_component.yml" -fi -if [ $? -ne 0 ]; then exit 1; fi - -# -# CLONE/UPDATE ESP-LITTLEFS -# -echo "Updating ESP-LITTLEFS..." -if [ ! -d "$AR_COMPS/esp_littlefs" ]; then - git clone $LITTLEFS_REPO_URL "$AR_COMPS/esp_littlefs" && \ - git -C "$AR_COMPS/esp_littlefs" submodule update --init --recursive -else - git -C "$AR_COMPS/esp_littlefs" fetch && \ - git -C "$AR_COMPS/esp_littlefs" pull --ff-only && \ - git -C "$AR_COMPS/esp_littlefs" submodule update --init --recursive -fi if [ $? -ne 0 ]; then exit 1; fi # @@ -117,37 +63,32 @@ if [ $? -ne 0 ]; then exit 1; fi echo "Updating ESP-RainMaker..." if [ ! -d "$AR_COMPS/esp-rainmaker" ]; then git clone $RMAKER_REPO_URL "$AR_COMPS/esp-rainmaker" && \ + git -C "$AR_COMPS/esp-rainmaker" reset --hard d8e93454f495bd8a414829ec5e86842b373ff555 && \ git -C "$AR_COMPS/esp-rainmaker" submodule update --init --recursive -else - git -C "$AR_COMPS/esp-rainmaker" fetch && \ - git -C "$AR_COMPS/esp-rainmaker" pull --ff-only && \ - git -C "$AR_COMPS/esp-rainmaker" submodule update --init --recursive +# else +# git -C "$AR_COMPS/esp-rainmaker" fetch && \ +# git -C "$AR_COMPS/esp-rainmaker" pull --ff-only && \ +# git -C "$AR_COMPS/esp-rainmaker" submodule update --init --recursive fi if [ $? -ne 0 ]; then exit 1; fi -# -# CLONE/UPDATE ESP-INSIGHTS -# -echo "Updating ESP-Insights..." -if [ ! -d "$AR_COMPS/esp-insights" ]; then - git clone $INSIGHTS_REPO_URL "$AR_COMPS/esp-insights" && \ - git -C "$AR_COMPS/esp-insights" submodule update --init --recursive -else - git -C "$AR_COMPS/esp-insights" fetch && \ - git -C "$AR_COMPS/esp-insights" pull --ff-only && \ - git -C "$AR_COMPS/esp-insights" submodule update --init --recursive +#this is a temp measure to fix build issue +if [ -f "$AR_COMPS/esp-rainmaker/components/esp-insights/components/esp_insights/scripts/get_projbuild_gitconfig.py" ] && [ `cat "$AR_COMPS/esp-rainmaker/components/esp-insights/components/esp_insights/scripts/get_projbuild_gitconfig.py" | grep esp32c6 | wc -l` == "0" ]; then + echo "Overwriting 'get_projbuild_gitconfig.py'" + cp -f "tools/get_projbuild_gitconfig.py" "$AR_COMPS/esp-rainmaker/components/esp-insights/components/esp_insights/scripts/get_projbuild_gitconfig.py" fi -if [ $? -ne 0 ]; then exit 1; fi # -# CLONE/UPDATE ESP-DSP +# CLONE/UPDATE ESP-LITTLEFS # -echo "Updating ESP-DSP..." -if [ ! -d "$AR_COMPS/espressif__esp-dsp" ]; then - git clone $DSP_REPO_URL "$AR_COMPS/espressif__esp-dsp" +echo "Updating ESP-LITTLEFS..." +if [ ! -d "$AR_COMPS/esp_littlefs" ]; then + git clone $LITTLEFS_REPO_URL "$AR_COMPS/esp_littlefs" && \ + git -C "$AR_COMPS/esp_littlefs" submodule update --init --recursive else - git -C "$AR_COMPS/espressif__esp-dsp" fetch && \ - git -C "$AR_COMPS/espressif__esp-dsp" pull --ff-only + git -C "$AR_COMPS/esp_littlefs" fetch && \ + git -C "$AR_COMPS/esp_littlefs" pull --ff-only && \ + git -C "$AR_COMPS/esp_littlefs" submodule update --init --recursive fi if [ $? -ne 0 ]; then exit 1; fi @@ -163,3 +104,16 @@ else fi if [ $? -ne 0 ]; then exit 1; fi +# +# CLONE/UPDATE TFLITE MICRO +# +echo "Updating TFLite Micro..." +if [ ! -d "$AR_COMPS/tflite-micro" ]; then + git clone $TFLITE_REPO_URL "$AR_COMPS/tflite-micro" + git -C "$AR_COMPS/tflite-micro" submodule update --init --recursive +else + git -C "$AR_COMPS/tflite-micro" fetch && \ + git -C "$AR_COMPS/tflite-micro" pull --ff-only + git -C "$AR_COMPS/tflite-micro" submodule update --init --recursive +fi +if [ $? -ne 0 ]; then exit 1; fi