diff --git a/firmware/MicroPython.bin b/firmware/MicroPython.bin index 754c215..6911052 100755 Binary files a/firmware/MicroPython.bin and b/firmware/MicroPython.bin differ diff --git a/firmware/MicroPython.kfpkg b/firmware/MicroPython.kfpkg index 15c9929..ad80897 100644 Binary files a/firmware/MicroPython.kfpkg and b/firmware/MicroPython.kfpkg differ diff --git a/firmware/MicroPython_firmwares.zip b/firmware/MicroPython_firmwares.zip index 9435ff4..8867239 100644 Binary files a/firmware/MicroPython_firmwares.zip and b/firmware/MicroPython_firmwares.zip differ diff --git a/firmware/ota/MicroPython.bin b/firmware/ota/MicroPython.bin index 3eb5874..d6f041a 100755 Binary files a/firmware/ota/MicroPython.bin and b/firmware/ota/MicroPython.bin differ diff --git a/firmware/ota/MicroPython.kfpkg b/firmware/ota/MicroPython.kfpkg index a76db09..55d64e5 100644 Binary files a/firmware/ota/MicroPython.kfpkg and b/firmware/ota/MicroPython.kfpkg differ diff --git a/firmware/sqlite/MicroPython.bin b/firmware/sqlite/MicroPython.bin index 6d24fee..30eadc2 100755 Binary files a/firmware/sqlite/MicroPython.bin and b/firmware/sqlite/MicroPython.bin differ diff --git a/firmware/sqlite/MicroPython.kfpkg b/firmware/sqlite/MicroPython.kfpkg index e72dcf3..4a44681 100644 Binary files a/firmware/sqlite/MicroPython.kfpkg and b/firmware/sqlite/MicroPython.kfpkg differ diff --git a/firmware/twotasks/MicroPython.bin b/firmware/twotasks/MicroPython.bin index c66726d..8f78bbb 100755 Binary files a/firmware/twotasks/MicroPython.bin and b/firmware/twotasks/MicroPython.bin differ diff --git a/firmware/twotasks/MicroPython.kfpkg b/firmware/twotasks/MicroPython.kfpkg index c66950d..956a6b1 100644 Binary files a/firmware/twotasks/MicroPython.kfpkg and b/firmware/twotasks/MicroPython.kfpkg differ diff --git a/k210-freertos/.config b/k210-freertos/.config index 24e02e8..2318277 100644 --- a/k210-freertos/.config +++ b/k210-freertos/.config @@ -61,6 +61,7 @@ CONFIG_MICROPY_USE_EPD=y CONFIG_MICROPY_USE_CAMERA=y CONFIG_MICROPY_PY_USE_GSM=y CONFIG_MICROPY_PY_USE_WIFI=y +# CONFIG_MICROPY_PY_USE_ESP32 is not set CONFIG_MICROPY_PY_USE_MQTT=y CONFIG_MICROPY_PY_USE_REQUESTS=y CONFIG_MICROPY_PY_USE_ULAB=y diff --git a/k210-freertos/.config.default b/k210-freertos/.config.default index 24e02e8..2318277 100644 --- a/k210-freertos/.config.default +++ b/k210-freertos/.config.default @@ -61,6 +61,7 @@ CONFIG_MICROPY_USE_EPD=y CONFIG_MICROPY_USE_CAMERA=y CONFIG_MICROPY_PY_USE_GSM=y CONFIG_MICROPY_PY_USE_WIFI=y +# CONFIG_MICROPY_PY_USE_ESP32 is not set CONFIG_MICROPY_PY_USE_MQTT=y CONFIG_MICROPY_PY_USE_REQUESTS=y CONFIG_MICROPY_PY_USE_ULAB=y diff --git a/k210-freertos/.config.ota b/k210-freertos/.config.ota index 580759f..e33b976 100644 --- a/k210-freertos/.config.ota +++ b/k210-freertos/.config.ota @@ -62,6 +62,7 @@ CONFIG_MICROPY_USE_EPD=y CONFIG_MICROPY_USE_CAMERA=y CONFIG_MICROPY_PY_USE_GSM=y CONFIG_MICROPY_PY_USE_WIFI=y +# CONFIG_MICROPY_PY_USE_ESP32 is not set CONFIG_MICROPY_PY_USE_MQTT=y CONFIG_MICROPY_PY_USE_REQUESTS=y CONFIG_MICROPY_PY_USE_ULAB=y diff --git a/k210-freertos/.config.sqlite b/k210-freertos/.config.sqlite index 036fe13..3397467 100644 --- a/k210-freertos/.config.sqlite +++ b/k210-freertos/.config.sqlite @@ -61,6 +61,7 @@ CONFIG_MICROPY_USE_EPD=y CONFIG_MICROPY_USE_CAMERA=y CONFIG_MICROPY_PY_USE_GSM=y CONFIG_MICROPY_PY_USE_WIFI=y +# CONFIG_MICROPY_PY_USE_ESP32 is not set CONFIG_MICROPY_PY_USE_MQTT=y CONFIG_MICROPY_PY_USE_REQUESTS=y CONFIG_MICROPY_PY_USE_ULAB=y diff --git a/k210-freertos/.config.twotasks b/k210-freertos/.config.twotasks index 6beb981..ab6430a 100644 --- a/k210-freertos/.config.twotasks +++ b/k210-freertos/.config.twotasks @@ -61,6 +61,7 @@ CONFIG_MICROPY_USE_EPD=y CONFIG_MICROPY_USE_CAMERA=y CONFIG_MICROPY_PY_USE_GSM=y CONFIG_MICROPY_PY_USE_WIFI=y +# CONFIG_MICROPY_PY_USE_ESP32 is not set CONFIG_MICROPY_PY_USE_MQTT=y CONFIG_MICROPY_PY_USE_REQUESTS=y CONFIG_MICROPY_PY_USE_ULAB=y diff --git a/k210-freertos/BUILD.sh b/k210-freertos/BUILD.sh index c4113de..d642029 100755 --- a/k210-freertos/BUILD.sh +++ b/k210-freertos/BUILD.sh @@ -161,41 +161,58 @@ fi # === build mconf ============================================== if [ ! -f "mconf" ] || [ ! -f "conf" ]; then - echo "=====[ BUILD: compiling 'menuconfig' files" - mkdir -p ../menuconfig/build - cd ../menuconfig/build - cmake .. #> /dev/null 2>&1 + echo "=====[ BUILD: compiling 'menuconfig' files" + mkdir -p ../menuconfig/build + cd ../menuconfig/build + cmake .. #> /dev/null 2>&1 if [ $? -eq 0 ]; then - make > /dev/null 2>&1 - if [ $? -eq 0 ]; then - cp mconf ../../k210-freertos > /dev/null 2>&1 - cp conf ../../k210-freertos > /dev/null 2>&1 - fi + make > /dev/null 2>&1 + if [ $? -eq 0 ]; then + cp mconf ../../k210-freertos > /dev/null 2>&1 + cp conf ../../k210-freertos > /dev/null 2>&1 + fi fi cd ../../k210-freertos - if [ ! -f "mconf" ] || [ ! -f "conf" ]; then - echo "=====[ BUILD: ERROR, 'menuconfig' files not compiled!" - exit 1 - fi - echo "=====[ BUILD: OK" + if [ ! -f "mconf" ] || [ ! -f "conf" ]; then + echo "=====[ BUILD: ERROR, 'menuconfig' files not compiled!" + exit 1 + fi + echo "=====[ BUILD: OK" sleep 1 fi # ============================================================== # ==== Select config file if requested ============================================ if [ "${USE_CONFIG_FILE}" != "" ]; then - echo "=====[ BUILD: use '${USE_CONFIG_FILE}' as config file" + echo "=====[ BUILD: use '${USE_CONFIG_FILE}' as config file" if [ -f "${USE_CONFIG_FILE}" ]; then - rm -f mpy_support/k210_config.h > /dev/null 2>&1 - cp -f .config .config.old > /dev/null 2>&1 - cp -f ${USE_CONFIG_FILE} .config > /dev/null 2>&1 - ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 - if [ $? -ne 0 ]; then - echo "=====[ BUILD: error creating 'k210.config.h'" - exit 1 - fi - echo "=====[ BUILD: Configuration files created." + rm -f mpy_support/k210_config.h > /dev/null 2>&1 + cp -f .config .config.old > /dev/null 2>&1 + cp -f ${USE_CONFIG_FILE} .config > /dev/null 2>&1 + ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "=====[ BUILD: error creating 'k210.config.h'" + if [ -t 1 ] ; then + # stdout is a terminal + ./mconf Kconfig + else + # stdout isn't a terminal + ./mconf Kconfig > $(tty) + fi + if [ $? -ne 0 ]; then + echo "=====[ BUILD: error running 'mconf'" + exit 1 + fi + cp -f .config .config.old > /dev/null 2>&1 + cp -f .config ${USE_CONFIG_FILE} > /dev/null 2>&1 + ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "=====[ BUILD: error creating 'k210.config.h'" + exit 1 + fi + fi + echo "=====[ BUILD: Configuration files created." else echo "=====[ BUILD: ERROR, '${USE_CONFIG_FILE}' not found!" fi @@ -204,38 +221,49 @@ fi if [ "${RUN_MENUCONFIG}" == "yes" ]; then - # ==== Run menuconfig if requested or needed ============================== - echo "=====[ BUILD: Running 'menuconfig'" - rm -f mpy_support/k210_config.h > /dev/null 2>&1 - ./mconf Kconfig + # ==== Run menuconfig if requested or needed ============================== + echo "=====[ BUILD: Running 'menuconfig'" + rm -f mpy_support/k210_config.h > /dev/null 2>&1 + ./mconf Kconfig if [ $? -ne 0 ]; then - echo "=====[ BUILD: error running 'mconf'" - exit 1 - fi - cp -f .config .config.old > /dev/null 2>&1 - ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 + echo "=====[ BUILD: error running 'mconf'" + exit 1 + fi + cp -f .config .config.old > /dev/null 2>&1 + ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 if [ $? -ne 0 ]; then - echo "=====[ BUILD: error creating 'k210.config.h'" - exit 1 - fi - echo "=====[ BUILD: Configuration files created." - echo "" - echo "=====[ BUILD: Run 'BUILD.sh' again to build the MicroPython firmware" - exit 0 - # ========================================================================= + echo "=====[ BUILD: error creating 'k210.config.h'" + exit 1 + fi + echo "=====[ BUILD: Configuration files created." + echo "" + echo "=====[ BUILD: Run 'BUILD.sh' again to build the MicroPython firmware" + exit 0 + # ========================================================================= else - # ==== Create 'k210.config.h' if not created ================================== - if [ ! -f "mpy_support/k210_config.h" ]; then - echo "=====[ BUILD: Creating 'k210.config.h'" - rm -f .config.old > /dev/null 2>&1 - ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 - if [ $? -ne 0 ]; then - echo "=====[ BUILD: error creating 'k210.config.h'" - exit 1 - fi - echo "=====[ BUILD: Configuration files created." - fi - # ============================================================================= + # ==== Create 'k210.config.h' if not created ================================== + if [ ! -f "mpy_support/k210_config.h" ]; then + echo "=====[ BUILD: Creating 'k210.config.h'" + rm -f .config.old > /dev/null 2>&1 + ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "=====[ BUILD: error creating 'k210.config.h'" + ./mconf Kconfig + if [ $? -ne 0 ]; then + echo "=====[ BUILD: error running 'mconf'" + exit 1 + fi + cp -f .config .config.old > /dev/null 2>&1 + cp -f .config ${USE_CONFIG_FILE} > /dev/null 2>&1 + ./conf --silentoldconfig mpy_support/k210_config.h Kconfig > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "=====[ BUILD: error creating 'k210.config.h'" + exit 1 + fi + fi + echo "=====[ BUILD: Configuration files created." + fi + # ============================================================================= fi # === build mklfs & create image ========= @@ -243,28 +271,28 @@ if [ ! -f "../mklittlefs/mklfs" ]; then echo "=====[ BUILD: compiling 'mklfs'" make -C ../mklittlefs > /dev/null 2>&1 if [ $? -eq 0 ]; then - echo "=====[ BUILD: ok." + echo "=====[ BUILD: ok." else - echo "=====[ BUILD: ERROR!" - exit 1 + echo "=====[ BUILD: ERROR!" + exit 1 fi sleep 1 fi rm -f ../mklittlefs/MicroPython_lfs.img > /dev/null 2>&1 if [ "${CREATE_FS_IMAGE}" == "yes" ]; then -cd ../mklittlefs -if [ "${VERBOSE_BUILD}" == "" ]; then -./mklfs internalfs_image MicroPython_lfs.img > /dev/null 2>&1 -else -./mklfs internalfs_image MicroPython_lfs.img -fi -if [ $? -eq 0 ]; then -echo "=====[ BUILD: File system image created" -else -echo "=====[ BUILD: File system image NOT created" -fi -cd ../k210-freertos + cd ../mklittlefs + if [ "${VERBOSE_BUILD}" == "" ]; then + ./mklfs internalfs_image MicroPython_lfs.img > /dev/null 2>&1 + else + ./mklfs internalfs_image MicroPython_lfs.img + fi + if [ $? -eq 0 ]; then + echo "=====[ BUILD: File system image created" + else + echo "=====[ BUILD: File system image NOT created" + fi + cd ../k210-freertos fi # ======================================= @@ -273,10 +301,10 @@ if [ ! -f "../micropython/mpy-cross/mpy-cross" ]; then echo "=====[ BUILD: compiling 'mpy-cross'" make -C ../micropython/mpy-cross ${J_OPTION} > /dev/null 2>&1 if [ $? -eq 0 ]; then - echo "=====[ BUILD: ok." + echo "=====[ BUILD: ok." else - echo "=====[ BUILD: ERROR!" - exit 1 + echo "=====[ BUILD: ERROR!" + exit 1 fi sleep 1 fi @@ -306,24 +334,24 @@ fi if [ "${MICROPY_OTA}" != "" ]; then echo "=====[ BUILD: compiling 'kboot'" - echo "/*" > ../Kboot/src/bootloader_hi/include/config.h - echo " * Defined from MicroPython build" >> ../Kboot/src/bootloader_hi/include/config.h - echo " */" >> ../Kboot/src/bootloader_hi/include/config.h - echo "#define FIRMWARE_SIZE ${MICROPY_FW_SIZE}" >> ../Kboot/src/bootloader_hi/include/config.h - echo "#define BOOT_PIN ${MICROPY_MBOOT_PIN}" >> ../Kboot/src/bootloader_hi/include/config.h - echo "" >> ../Kboot/src/bootloader_hi/include/config.h - cd ../Kboot/build - ./BUILD.sh + echo "/*" > ../Kboot/src/bootloader_hi/include/config.h + echo " * Defined from MicroPython build" >> ../Kboot/src/bootloader_hi/include/config.h + echo " */" >> ../Kboot/src/bootloader_hi/include/config.h + echo "#define FIRMWARE_SIZE ${MICROPY_FW_SIZE}" >> ../Kboot/src/bootloader_hi/include/config.h + echo "#define BOOT_PIN ${MICROPY_MBOOT_PIN}" >> ../Kboot/src/bootloader_hi/include/config.h + echo "" >> ../Kboot/src/bootloader_hi/include/config.h + cd ../Kboot/build + ./BUILD.sh if [ $? -eq 0 ]; then - echo "=====[ BUILD: ok." + echo "=====[ BUILD: ok." else - cd ../../k210-freertos - echo "=====[ BUILD: ERROR!" - exit 1 + cd ../../k210-freertos + echo "=====[ BUILD: ERROR!" + exit 1 fi - cd ../../k210-freertos - cp -f ../Kboot/build/bootloader_??.bin . - cp -f ../Kboot/build/config.bin . + cd ../../k210-freertos + cp -f ../Kboot/build/bootloader_??.bin . + cp -f ../Kboot/build/config.bin . fi MICROPY_VER=$( cat mpy_support/mpconfigport.h | grep "MICROPY_PY_LOBO_VERSION" | cut -d'"' -s -f 2 ) @@ -334,14 +362,14 @@ FLASH_START_ADDRES=$(( ${MICROPY_FLASH_START} * 1024 * 1024 )) FS_USED=$( cat mpy_support/k210_config.h | grep "CONFIG_MICROPY_FILESYSTEM_TYPE" | cut -d' ' -s -f 3 ) if [ "${FS_USED}" == "0" ]; then - # === Do not compile spiffs if not used === - if [ -f third_party/spiffs/Makefile ]; then - mv third_party/spiffs/Makefile third_party/spiffs/Makefile.notused > /dev/null 2>&1 - fi + # === Do not compile spiffs if not used === + if [ -f third_party/spiffs/Makefile ]; then + mv third_party/spiffs/Makefile third_party/spiffs/Makefile.notused > /dev/null 2>&1 + fi else - if [ -f third_party/spiffs/Makefile.notused ]; then - mv third_party/spiffs/Makefile.notused third_party/spiffs/Makefile - fi + if [ -f third_party/spiffs/Makefile.notused ]; then + mv third_party/spiffs/Makefile.notused third_party/spiffs/Makefile + fi fi # -------------------------------------------------------- @@ -369,18 +397,18 @@ echo "" echo "=====[ BUILD: UPDATE mk files" make update_mk > /dev/null if [ $? -ne 0 ]; then -echo "=====[ BUILD: ERROR!" -exit 1 + echo "=====[ BUILD: ERROR!" + exit 1 fi if [ "${VERBOSE_BUILD}" == "yes" ] || [ "${VERBOSE_BUILD}" == "yesyes" ]; then -make update_mk + make update_mk else -make update_mk > /dev/null + make update_mk > /dev/null fi if [ $? -ne 0 ]; then -echo "=====[ BUILD: ERROR!" -exit 1 + echo "=====[ BUILD: ERROR!" + exit 1 fi echo "" @@ -393,14 +421,14 @@ export PLATFORM=k210 export MAKE_OPT="${J_OPTION}" if [ "${VERBOSE_BUILD}" == "yes" ]; then -export BUILD_VERBOSE=0 -make all + export BUILD_VERBOSE=0 + make all elif [ "${VERBOSE_BUILD}" == "yesyes" ]; then -export BUILD_VERBOSE=1 -make all + export BUILD_VERBOSE=1 + make all else -export BUILD_VERBOSE=0 -make all > /dev/null + export BUILD_VERBOSE=0 + make all > /dev/null fi # =============================================================================== @@ -411,9 +439,9 @@ fi if [ $? -eq 0 ]; then if [ "${machine}" == "MacOS" ]; then -FILESIZE=$(stat -s MicroPython.bin | cut -d' ' -s -f 1 | cut -d'=' -s -f 2) + FILESIZE=$(stat -s MicroPython.bin | cut -d' ' -s -f 1 | cut -d'=' -s -f 2) else -FILESIZE=$(stat -c%s MicroPython.bin) + FILESIZE=$(stat -c%s MicroPython.bin) fi ALIGNED_SIZE=$(( (((${FILESIZE} / 4096) * 4096)) + 8192 )) # Code in SRAM starts at 0x80000000, correct the address @@ -426,14 +454,14 @@ mv MicroPython.bin MicroPython.bin.bkp # Get real file size if [ "${machine}" == "MacOS" ]; then -FILESIZE=$(stat -s MicroPython.bin | cut -d' ' -s -f 1 | cut -d'=' -s -f 2) + FILESIZE=$(stat -s MicroPython.bin | cut -d' ' -s -f 1 | cut -d'=' -s -f 2) else -FILESIZE=$(stat -c%s MicroPython.bin) + FILESIZE=$(stat -c%s MicroPython.bin) fi if [ "${CREATE_DUMP}" == "yes" ]; then -echo "=====[ BUILD: Exporting objdump" -../kendryte-toolchain/bin/riscv64-unknown-elf-objdump -S --disassemble MicroPython > MicroPython.dump + echo "=====[ BUILD: Exporting objdump" + ../kendryte-toolchain/bin/riscv64-unknown-elf-objdump -S --disassemble MicroPython > MicroPython.dump fi # ========================================= @@ -441,106 +469,106 @@ fi # ========================================= if [ "${MICROPY_OTA}" != "" ]; then -echo "" -echo "=====[ BUILD: Creating 'MicroPython.kfpkg' (OTA)" -rm -f *.img > /dev/null 2>&1 -echo "{" > flash-list.json -echo " \"version\": \"0.1.0\"," >> flash-list.json -echo " \"files\": [">> flash-list.json -echo " {">> flash-list.json -echo " \"address\": 0,">> flash-list.json -echo " \"bin\": \"bootloader_lo.bin\",">> flash-list.json -echo " \"sha256Prefix\": true">> flash-list.json -echo " },">> flash-list.json -echo " {">> flash-list.json -echo " \"address\": 4096,">> flash-list.json -echo " \"bin\": \"bootloader_hi.bin\",">> flash-list.json -echo " \"sha256Prefix\": true">> flash-list.json -echo " },">> flash-list.json -echo " {">> flash-list.json -echo " \"address\": 16384,">> flash-list.json -echo " \"bin\": \"config.bin\",">> flash-list.json -echo " \"sha256Prefix\": false">> flash-list.json -echo " },">> flash-list.json -echo " {">> flash-list.json -echo " \"address\": 20480,">> flash-list.json -echo " \"bin\": \"config.bin\",">> flash-list.json -echo " \"sha256Prefix\": false">> flash-list.json -echo " },">> flash-list.json -echo " {">> flash-list.json -echo " \"address\": 65536,">> flash-list.json -echo " \"bin\": \"MicroPython.bin\",">> flash-list.json -echo " \"sha256Prefix\": true,">> flash-list.json -echo " \"swap\": false">> flash-list.json -if [ -f "${PWD}/../mklittlefs/MicroPython_lfs.img" ]; then -cp ${PWD}/../mklittlefs/MicroPython_lfs.img . -echo " },">> flash-list.json -echo " {">> flash-list.json -echo " \"address\": ${FLASH_START_ADDRES},">> flash-list.json -echo " \"bin\": \"MicroPython_lfs.img\",">> flash-list.json -echo " \"sha256Prefix\": false,">> flash-list.json -echo " \"swap\": false">> flash-list.json -echo " }">> flash-list.json -else -echo " }">> flash-list.json -fi -echo " ]">> flash-list.json -echo "}">> flash-list.json -else -echo "" -echo "=====[ BUILD: Creating 'MicroPython.kfpkg'" -rm -f *.img > /dev/null 2>&1 -echo "{" > flash-list.json -echo " \"version\": \"0.1.0\"," >> flash-list.json -echo " \"files\": [">> flash-list.json -echo " {">> flash-list.json -echo " \"address\": 0,">> flash-list.json -echo " \"bin\": \"MicroPython.bin\",">> flash-list.json -echo " \"sha256Prefix\": true,">> flash-list.json -echo " \"swap\": false">> flash-list.json -if [ -f "${PWD}/../mklittlefs/MicroPython_lfs.img" ]; then -cp ${PWD}/../mklittlefs/MicroPython_lfs.img . -echo " },">> flash-list.json -echo " {">> flash-list.json -echo " \"address\": ${FLASH_START_ADDRES},">> flash-list.json -echo " \"bin\": \"MicroPython_lfs.img\",">> flash-list.json -echo " \"sha256Prefix\": false,">> flash-list.json -echo " \"swap\": false">> flash-list.json -echo " }">> flash-list.json + echo "" + echo "=====[ BUILD: Creating 'MicroPython.kfpkg' (OTA)" + rm -f *.img > /dev/null 2>&1 + echo "{" > flash-list.json + echo " \"version\": \"0.1.0\"," >> flash-list.json + echo " \"files\": [">> flash-list.json + echo " {">> flash-list.json + echo " \"address\": 0,">> flash-list.json + echo " \"bin\": \"bootloader_lo.bin\",">> flash-list.json + echo " \"sha256Prefix\": true">> flash-list.json + echo " },">> flash-list.json + echo " {">> flash-list.json + echo " \"address\": 4096,">> flash-list.json + echo " \"bin\": \"bootloader_hi.bin\",">> flash-list.json + echo " \"sha256Prefix\": true">> flash-list.json + echo " },">> flash-list.json + echo " {">> flash-list.json + echo " \"address\": 16384,">> flash-list.json + echo " \"bin\": \"config.bin\",">> flash-list.json + echo " \"sha256Prefix\": false">> flash-list.json + echo " },">> flash-list.json + echo " {">> flash-list.json + echo " \"address\": 20480,">> flash-list.json + echo " \"bin\": \"config.bin\",">> flash-list.json + echo " \"sha256Prefix\": false">> flash-list.json + echo " },">> flash-list.json + echo " {">> flash-list.json + echo " \"address\": 65536,">> flash-list.json + echo " \"bin\": \"MicroPython.bin\",">> flash-list.json + echo " \"sha256Prefix\": true,">> flash-list.json + echo " \"swap\": false">> flash-list.json + if [ -f "${PWD}/../mklittlefs/MicroPython_lfs.img" ]; then + cp ${PWD}/../mklittlefs/MicroPython_lfs.img . + echo " },">> flash-list.json + echo " {">> flash-list.json + echo " \"address\": ${FLASH_START_ADDRES},">> flash-list.json + echo " \"bin\": \"MicroPython_lfs.img\",">> flash-list.json + echo " \"sha256Prefix\": false,">> flash-list.json + echo " \"swap\": false">> flash-list.json + echo " }">> flash-list.json + else + echo " }">> flash-list.json + fi + echo " ]">> flash-list.json + echo "}">> flash-list.json else -echo " }">> flash-list.json -fi -echo " ]">> flash-list.json -echo "}">> flash-list.json + echo "" + echo "=====[ BUILD: Creating 'MicroPython.kfpkg'" + rm -f *.img > /dev/null 2>&1 + echo "{" > flash-list.json + echo " \"version\": \"0.1.0\"," >> flash-list.json + echo " \"files\": [">> flash-list.json + echo " {">> flash-list.json + echo " \"address\": 0,">> flash-list.json + echo " \"bin\": \"MicroPython.bin\",">> flash-list.json + echo " \"sha256Prefix\": true,">> flash-list.json + echo " \"swap\": false">> flash-list.json + if [ -f "${PWD}/../mklittlefs/MicroPython_lfs.img" ]; then + cp ${PWD}/../mklittlefs/MicroPython_lfs.img . + echo " },">> flash-list.json + echo " {">> flash-list.json + echo " \"address\": ${FLASH_START_ADDRES},">> flash-list.json + echo " \"bin\": \"MicroPython_lfs.img\",">> flash-list.json + echo " \"sha256Prefix\": false,">> flash-list.json + echo " \"swap\": false">> flash-list.json + echo " }">> flash-list.json + else + echo " }">> flash-list.json + fi + echo " ]">> flash-list.json + echo "}">> flash-list.json fi if [ "${MICROPY_OTA}" != "" ]; then - rm -f *.kfpkg > /dev/null 2>&1 - if [ -f MicroPython_lfs.img ]; then - zip MicroPython.kfpkg -9 flash-list.json bootloader_lo.bin bootloader_hi.bin config.bin MicroPython.bin MicroPython_lfs.img > /dev/null - else - zip MicroPython.kfpkg -9 flash-list.json bootloader_lo.bin bootloader_hi.bin config.bin MicroPython.bin > /dev/null - fi - rm -f bootloader_??.bin - rm -f config.bin + rm -f *.kfpkg > /dev/null 2>&1 + if [ -f MicroPython_lfs.img ]; then + zip MicroPython.kfpkg -9 flash-list.json bootloader_lo.bin bootloader_hi.bin config.bin MicroPython.bin MicroPython_lfs.img > /dev/null + else + zip MicroPython.kfpkg -9 flash-list.json bootloader_lo.bin bootloader_hi.bin config.bin MicroPython.bin > /dev/null + fi + rm -f bootloader_??.bin + rm -f config.bin else - rm -f *.kfpkg > /dev/null 2>&1 - if [ -f MicroPython_lfs.img ]; then - zip MicroPython.kfpkg -9 flash-list.json MicroPython.bin MicroPython_lfs.img > /dev/null - else - zip MicroPython.kfpkg -9 flash-list.json MicroPython.bin > /dev/null - fi + rm -f *.kfpkg > /dev/null 2>&1 + if [ -f MicroPython_lfs.img ]; then + zip MicroPython.kfpkg -9 flash-list.json MicroPython.bin MicroPython_lfs.img > /dev/null + else + zip MicroPython.kfpkg -9 flash-list.json MicroPython.bin > /dev/null + fi fi if [ $? -eq 0 ]; then if [ -f "${PWD}/../mklittlefs/MicroPython_lfs.img" ]; then -echo "=====[ BUILD: kfpkg created" -else -echo "=====[ BUILD: kfpkg created without FS image)" -fi + echo "=====[ BUILD: kfpkg created" + else + echo "=====[ BUILD: kfpkg created without FS image)" + fi else -echo "=====[ BUILD: ERROR creating kfpkg" -exit 1 + echo "=====[ BUILD: ERROR creating kfpkg" + exit 1 fi rm -f *.img > /dev/null 2>&1 rm -f *.json > /dev/null 2>&1 @@ -548,10 +576,10 @@ rm -f *.json > /dev/null 2>&1 echo if [ "${VERBOSE_BUILD}" == "" ]; then -echo "---------------------------------------------------" -../kendryte-toolchain/bin/riscv64-unknown-elf-size MicroPython -echo "---------------------------------------------------" -echo + echo "---------------------------------------------------" + ../kendryte-toolchain/bin/riscv64-unknown-elf-size MicroPython + echo "---------------------------------------------------" + echo fi @@ -561,15 +589,14 @@ echo " version: ${MICROPY_VER}" echo " Firmware file size: ${FILESIZE}" MICROPY_FILE_CRC32=$(crc32 MicroPython.bin 2> /dev/null) if [ $? -eq 0 ]; then -echo " Firmware CRC32: ${MICROPY_FILE_CRC32}" -fi -echo " Flash FS starts at: ${FLASH_START_ADDRES}" -echo "=============================" + echo " Firmware CRC32: ${MICROPY_FILE_CRC32}" + fi + echo " Flash FS starts at: ${FLASH_START_ADDRES}" + echo "=============================" else - -echo "====================" -echo "==== Build ERROR ===" -echo "====================" + echo "====================" + echo "==== Build ERROR ===" + echo "====================" fi diff --git a/k210-freertos/CLEAN.sh b/k210-freertos/CLEAN.sh index eabd41a..e5de448 100755 --- a/k210-freertos/CLEAN.sh +++ b/k210-freertos/CLEAN.sh @@ -3,6 +3,7 @@ cd k210-freertos > /dev/null 2>&1 rm -Rf build/* > /dev/null 2>&1 +rm -Rf ../menuconfig/build/* > /dev/null 2>&1 rm -Rf mpy_support/build/* > /dev/null 2>&1 make -C ../micropython/mpy-cross clean -s V=1 diff --git a/k210-freertos/Kconfig b/k210-freertos/Kconfig index 4699958..15a954a 100644 --- a/k210-freertos/Kconfig +++ b/k210-freertos/Kconfig @@ -328,6 +328,14 @@ mainmenu "MicroPython for Kendryte K210" Some K210 boards (like MAIX-M1, DanDock) already have ESP8266 attached to K210 UART. For other boards, any ESP8266/ESP8285 board or module can be simply attached, only Tx, Rx and GND are needed. + config MICROPY_PY_USE_ESP32 + bool "ESP32 module (experimental!)" + default n + help + Enables using ESP32 over SPI interface. + Mostly used for accessing the network resources, but can also be used for accessing other ESP32 peripherals. + Not yet fully functional! + config MICROPY_PY_USE_MQTT bool "Mqtt module" default y diff --git a/k210-freertos/changelog.txt b/k210-freertos/changelog.txt index 2c56850..351276a 100755 --- a/k210-freertos/changelog.txt +++ b/k210-freertos/changelog.txt @@ -1,3 +1,40 @@ +=================== +Date: Mar 12 2020 +=================== + +'ota' module updated + - update can be performed via 'requests.get' + - some bug fixes and improveents + +'ulab' module updated to latest GitHub master + +MicroPython core updated + - backported some code needed to run latest 'ulab + - objexcept.c, sequence.c, obkstrunicode.c, + objslice.c, runtime.h, runtime.c, obj.h + +'machine' module updated + +'spi' module updated + - many changes to SPI slave + +updated littlefs 'trim' function + +'network' module updated + - TLS/SSL is now available for GSM connections + - secure connection in sockets, requests and mqtt now works over GSM connection + +'requests' module updated + - support for OTA update added + - resume download is now implemented + +fixed bug in 'uart' module + +bug fixes in mbedtls (FreeRTOS) + +other bugfixes and improvements + + =================== Date: Feb 06 2020 =================== diff --git a/k210-freertos/main.c b/k210-freertos/main.c index 34c0a2f..d5431fe 100755 --- a/k210-freertos/main.c +++ b/k210-freertos/main.c @@ -391,10 +391,6 @@ static void mp_task_proc1(void *pvParameter) //======== int main() { - uint32_t *ld_mbootid = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR); - uint32_t *ld_address = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR+4); - uint32_t *ld_size = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR+8); - // ==== Basic initialization ==== // Setup clocks (default clocks set in 'entry_user.c') /* @@ -408,7 +404,6 @@ int main() sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI3, 0); sysctl_clock_set_clock_select(SYSCTL_CLOCK_SELECT_SPI3, 1); - sys_us_counter_cpu = read_csr64(mcycle); uarths_baudrate = uarths_init(MICRO_PY_DEFAULT_BAUDRATE); // ==== Get reset status ==== @@ -462,11 +457,16 @@ int main() user_log_level = mpy_config.config.log_level; user_log_color = mpy_config.config.log_color; - vTaskDelay(2); + vTaskDelay(5); + printf("\n"); if (cfg_loaded) LOGM(TAG, "Configuration loaded from flash"); else LOGM(TAG, "Default flash configuration set"); #if MICROPY_PY_USE_OTA + uint32_t *ld_mbootid = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR); + uint32_t *ld_address = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR+4); + uint32_t *ld_size = (uint32_t *)(MICROPY_SYS_RAMBUF_ADDR+8); + if (*ld_mbootid == MICROPY_MBOOT_MAGIC_ID) { if (*ld_address & 0x80000000) { *ld_address &= 0x7fffffff; diff --git a/k210-freertos/mpy_support/modota.c b/k210-freertos/mpy_support/modota.c index 9d5d492..9ce5734 100644 --- a/k210-freertos/mpy_support/modota.c +++ b/k210-freertos/mpy_support/modota.c @@ -109,7 +109,6 @@ #include #include #include "w25qxx.h" -#include "sha256_hard.h" #include "spi.h" #include "syslog.h" #include "mphalport.h" @@ -117,38 +116,10 @@ #include "py/runtime.h" #include "extmod/vfs.h" #include "py/stream.h" +#include "modota.h" - -#define BOOT_CONFIG_ADDR 0x00004000 // main boot config sector in flash at 52K -#define BOOT_CONFIG_ITEMS 8 // number of handled config entries -#define BOOT_CONFIG_ITEM_SIZE 32 // size of config entry -#define BOOT_CONFIG_SECTOR_SIZE 4096 -#define BOOT_MAIN_SECTOR 1 -#define BOOT_BACKUP_SECTOR 2 - -#define MAGIC_ID 0x5AA5D0C0 -#define MAGIC_ID_FLAG 0xA55A60C0 -#define MAGIC_ID_MASK 0xFFFFFFF0 -#define CFG_APP_FLAG_ACTIVE 0x00000001 -#define CFG_APP_FLAG_CRC32 0x00000002 -#define CFG_APP_FLAG_SHA256 0x00000004 -#define CFG_APP_FLAG_SIZE 0x00000008 - -#define DEFAULT_APP_ADDRESS 0x00010000 -#define BOOT_ENTRY_NAME_LEN 16 - - -typedef struct _ota_entry_t { - uint32_t id_flags; - uint32_t address; - uint32_t size; - uint32_t crc32; - char name[BOOT_ENTRY_NAME_LEN]; -} __attribute__((packed, aligned(4))) ota_entry_t; - - -static uint8_t config_sector[BOOT_CONFIG_SECTOR_SIZE]; -static uint8_t config_loaded = 0; +uint8_t config_sector[BOOT_CONFIG_SECTOR_SIZE]; +uint8_t config_loaded = 0; static const char* TAG = "[OTA]"; /* @@ -169,17 +140,18 @@ static void _swap_endianess(uint8_t *buff, int len) /* * Get uint32_t value from Flash - * 8-bit Flash pointer is used, so the byte order must be swapped * This is used when reading from not 4-byte aligned locations - * XIP must be already enabled! + * !! XiP mode MUST be enabled */ -//----------------------------------------- -static uint32_t flash2uint32(uint32_t addr) +//---------------------------------- +uint32_t flash2uint32(uint32_t addr) { + //w25qxx_enable_xip_mode(); uint32_t val = w25qxx_flash_ptr[addr]; val += w25qxx_flash_ptr[addr+1] << 8; val += w25qxx_flash_ptr[addr+2] << 16; val += w25qxx_flash_ptr[addr+3] << 24; + //w25qxx_disable_xip_mode(); return val; } @@ -209,8 +181,8 @@ static void config_swap_endianess() } // Read config sector into buffer -//------------------------------------------------ -static bool read_config(uint8_t n_conf, bool swap) +//----------------------------------------- +bool read_config(uint8_t n_conf, bool swap) { if (config_loaded == n_conf) return true; @@ -230,8 +202,8 @@ static bool read_config(uint8_t n_conf, bool swap) } // Backup main config sector to backup config sector -//------------------------------ -static bool backup_boot_sector() +//----------------------- +bool backup_boot_sector() { bool curr_spi_check = w25qxx_spi_check; w25qxx_spi_check = true; @@ -256,8 +228,8 @@ static bool backup_boot_sector() } // Restore main config sector from backup -//------------------------------- -static bool restore_boot_sector() +//------------------------ +bool restore_boot_sector() { bool curr_spi_check = w25qxx_spi_check; w25qxx_spi_check = true; @@ -284,8 +256,8 @@ static bool restore_boot_sector() } // Write modified boot sector from buffer to Flash -//----------------------------- -static bool write_boot_sector() +//---------------------- +bool write_boot_sector() { // Save modified boot sector config_swap_endianess(); @@ -310,19 +282,19 @@ static bool write_boot_sector() } /* - * Calculate the firmware's SHA256 hash and get the stored SHA256 + * Calculate the firmware's SHA256 hash and get the stored SHA256 (is requested) * Complete firmware, including 5-byte prefix and 32-byte SHA hash, is expected at flash address * The hash is 32 bytes long and written after the firmware's code * The hash is calculated over 5-byte prefix and firmware's code ! * by Ktool or other application */ -//----------------------------------------------------------------------------- -static void calc_app_sha256(uint32_t address, uint8_t *hash, uint8_t *app_hash) +//---------------------------------------------------------------------- +void calc_app_sha256(uint32_t address, uint8_t *hash, uint8_t *app_hash) { w25qxx_enable_xip_mode(); - memset(hash, 0, SHA256_HASH_LEN); - memset(app_hash, 0, SHA256_HASH_LEN); + memset(hash, 0, SHA256_HASH_LEN); // calculated hash + if (app_hash) memset(app_hash, 0, SHA256_HASH_LEN); // stored hash sha256_hard_context_t context; uint8_t buffer[1024] = {0}; @@ -345,14 +317,67 @@ static void calc_app_sha256(uint32_t address, uint8_t *hash, uint8_t *app_hash) sha256_hard_final(&context, hash); - // get the application's SHA256 hash - for (int n=0; n 0) { + sz = (size >= 1024) ? 1024 : size; + for (int n=0; n> 8) ^ Crc32LookupTable[(crc & 0xFF) ^ byte]; + /* crc = crc ^ byte; for (uint32_t j = 0; j < 8; j++) { mask = -(crc & 1); crc = (crc >> 1) ^ (0xEDB88320 & mask); } + */ } w25qxx_disable_xip_mode(); @@ -422,8 +451,8 @@ static bool app_crc32(ota_entry_t *entry, uint32_t *crc32) } // Get the size of the firmware at Flash address -//-------------------------------------------------- -static uint32_t get_fw_flash_size(uint32_t address) +//------------------------------------------ +uint32_t get_fw_flash_size(uint32_t address) { w25qxx_enable_xip_mode(); uint32_t app_size = flash2uint32(address+1); @@ -431,6 +460,19 @@ static uint32_t get_fw_flash_size(uint32_t address) return app_size; } +//----------------------------------- +bool check_deadbeef(uint32_t address) +{ + w25qxx_enable_xip_mode(); + uint32_t id = flash2uint32(address+9); + w25qxx_disable_xip_mode(); + if (id != K210_APP_ID) { + LOGD(TAG, "App ID wrong (%08X)", id); + return false; + } + return true; +} + // Check the config sector entry //---------------------------------------------------------- static uint8_t check_entry(ota_entry_t *entry, char *status) @@ -443,7 +485,7 @@ static uint8_t check_entry(ota_entry_t *entry, char *status) uint8_t flags = entry->id_flags & 0x0f; if (app_size != entry->size) { - if (status) strcat(status, "Size mismatch! "); + if (status) strcat(status, "[Size mismatch] "); stat |= 1; } if (flags & CFG_APP_FLAG_SIZE) { @@ -456,19 +498,23 @@ static uint8_t check_entry(ota_entry_t *entry, char *status) if (flags & CFG_APP_FLAG_CRC32) { uint32_t crc32; if (!app_crc32(entry, &crc32)) { - if (status) strcat(status, "CRC32 Error "); + if (status) strcat(status, "[CRC32 Error] "); stat |= 4; return stat; } } if (flags & CFG_APP_FLAG_SHA256) { if (!check_app_sha256(entry->address)) { - if (status) strcat(status, "SHA256 Error "); + if (status) strcat(status, "[SHA256 Error] "); stat |= 8; return stat; } } - if (status) strcat(status, "Check OK "); + if (status) strcat(status, "[Check OK] "); + if (!check_deadbeef(entry->address)) { + stat |= 16; + if (status) strcat(status, "[Not K210 app] "); + } return stat; } @@ -614,8 +660,8 @@ static bool firmware_write(mp_obj_t ffd, uint32_t dest, uint32_t size, bool prog } // Get the 1st active firmware from the main config sector -//---------------------------- -static int config_get_active() +//--------------------- +int config_get_active() { if (!read_config(BOOT_MAIN_SECTOR, true)) return -1; @@ -645,7 +691,7 @@ static bool config_set_active(uint8_t n_entry) ota_entry_t *entry; uint8_t stat, flags; bool f = false; - char status[32]; + char status[64]; for (int i=0; i < BOOT_CONFIG_ITEMS; i++) { entry = (ota_entry_t *)(config_sector + (i*BOOT_CONFIG_ITEM_SIZE)); @@ -727,7 +773,7 @@ STATIC mp_obj_t mod_ota_list(size_t n_args, const mp_obj_t *pos_args, mp_map_t * uint8_t flags; ota_entry_t *entry; char sflags[32]; - char status[32]; + char status[64]; uint8_t stat; int n_entries = 0; mp_obj_t entry_tuple[6]; @@ -804,7 +850,7 @@ STATIC mp_obj_t mod_ota_clone(size_t n_args, const mp_obj_t *pos_args, mp_map_t int dest = args[ARG_dest].u_int; if ((dest < 0) || (dest > (BOOT_CONFIG_ITEMS-1))) { - mp_raise_ValueError("Wrong dest index"); + mp_raise_ValueError("Wrong OTA destination index"); } uint32_t dest_address = (uint32_t)args[ARG_address].u_int & 0xFFFFF000; uint32_t src_address, src_end_address, src_size, dest_end_address; @@ -885,7 +931,7 @@ STATIC mp_obj_t mod_ota_fw_fromfile(size_t n_args, const mp_obj_t *pos_args, mp_ uint32_t dest_address = (uint32_t)args[ARG_address].u_int & 0xFFFFF000; int dest = args[ARG_dest].u_int; if ((dest < 0) || (dest > (BOOT_CONFIG_ITEMS-1))) { - mp_raise_ValueError("Wrong dest index"); + mp_raise_ValueError("Wrong OTA destination index"); } char entry_name[BOOT_ENTRY_NAME_LEN] = {'\0'}; diff --git a/k210-freertos/mpy_support/modota.h b/k210-freertos/mpy_support/modota.h new file mode 100644 index 0000000..9661028 --- /dev/null +++ b/k210-freertos/mpy_support/modota.h @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython K210 project, https://github.com/loboris/MicroPython_K210_LoBo + * + * The MIT License (MIT) + * + * Copyright (c) 2020 LoBo (https://github.com/loboris) + * + * 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. + */ + +#include "sha256_hard.h" + +#define BOOT_CONFIG_ADDR 0x00004000 // main boot config sector in flash at 52K +#define BOOT_CONFIG_ITEMS 8 // number of handled config entries +#define BOOT_CONFIG_ITEM_SIZE 32 // size of config entry +#define BOOT_CONFIG_SECTOR_SIZE 4096 +#define BOOT_MAIN_SECTOR 1 +#define BOOT_BACKUP_SECTOR 2 + +#define MAGIC_ID 0x5AA5D0C0 +#define MAGIC_ID_FLAG 0xA55A60C0 +#define MAGIC_ID_MASK 0xFFFFFFF0 +#define CFG_APP_FLAG_ACTIVE 0x00000001 +#define CFG_APP_FLAG_CRC32 0x00000002 +#define CFG_APP_FLAG_SHA256 0x00000004 +#define CFG_APP_FLAG_SIZE 0x00000008 + +#define K210_APP_ID 0xDEADBEEF +#define DEFAULT_APP_ADDRESS 0x00010000 +#define BOOT_ENTRY_NAME_LEN 16 + + +typedef struct _ota_entry_t { + uint32_t id_flags; + uint32_t address; + uint32_t size; + uint32_t crc32; + char name[BOOT_ENTRY_NAME_LEN]; +} __attribute__((packed, aligned(4))) ota_entry_t; + + +extern uint8_t config_sector[BOOT_CONFIG_SECTOR_SIZE]; +extern uint8_t config_loaded; + +bool write_boot_sector(); +bool read_config(uint8_t n_conf, bool swap); +bool backup_boot_sector(); +bool restore_boot_sector(); +int config_get_active(); + +uint32_t flash2uint32(uint32_t addr); +bool uint32toflash(uint32_t addr, uint32_t val); +uint32_t calc_app_crc32(uint32_t address, uint32_t size); +bool calc_set_app_sha256(uint32_t address); +bool check_app_sha256(uint32_t address); +void calc_app_sha256(uint32_t address, uint8_t *hash, uint8_t *app_hash); +uint32_t get_fw_flash_size(uint32_t address); diff --git a/k210-freertos/mpy_support/mpconfigport.h b/k210-freertos/mpy_support/mpconfigport.h index 3934ef0..bfbf22f 100755 --- a/k210-freertos/mpy_support/mpconfigport.h +++ b/k210-freertos/mpy_support/mpconfigport.h @@ -53,7 +53,7 @@ extern uint32_t _ram_end; #define MICROPY_HW_MCU_NAME CONFIG_MICROPY_HW_MCU_NAME #define MICROPY_PY_SYS_PLATFORM "K210/FreeRTOS" -#define MICROPY_PY_LOBO_VERSION "1.12.01" +#define MICROPY_PY_LOBO_VERSION "1.12.02" #define MICROPY_PY_LOBO_VERSION_NUM (0x011201) #ifdef CONFIG_MICROPY_PY_USE_LOG_COLORS @@ -129,6 +129,13 @@ extern uint32_t _ram_end; * - thread's (task's) stacks and all buffers are allocated from FreeRTOS heap * - If two MicroPython instances are configured, the available heap space is divided between them, * default values are: 5/8 for 1st MicroPython instance and 3/8 for the 2nd + * ---------------------------------------------------------------------- + * !!! IMPORTANT !!! + * ---------------------------------------------------------------------- + * When KPU memory is used to expand the FreeRTOS heap + * some variables (on task stack or on FreeRTOS heap) may be placed + * at SRAM address above 0x80600000 ! + * Those variables CAN'T be used in DMA transfers involving peripherals ! * ============================================================================================================= */ @@ -147,12 +154,16 @@ extern uint32_t _ram_end; * 1 - 2.5 MB of SRAM is used for the firmware * 2 - 3 MB of SRAM is used for the firmware * 3 - 3.5 MB of SRAM is used for the firmware + * -------------------------------------------------------- + * This area contains the firmware code, defined constants, + * and all declared variables. Remaining space is used as + * system heap (for 'malloc' function). * ======================================================== */ /* * SRAM size reserved for the firmware - * if sqlite is compiled, 3MB must be used + * if sqlite is compiled, at least 3MB must be used * */ #if (CONFIG_FIRMWARE_SIZE_TYPE == 0) @@ -165,31 +176,21 @@ extern uint32_t _ram_end; #define FIRMWARE_SRAM_SIZE (0x380000UL) #endif -// === Size of the SRAM area used for RAMBUFFER -// variables placed in this area will be preserved after reset +/* + * Size of the SRAM area used for RAMBUFFER + * variables placed in this area will be preserved after reset + * This area i placed after end of firmware area (at 'FIRMWARE_SRAM_SIZE') + */ #define MYCROPY_SYS_RAMBUF_SIZE 4096 +#define MICROPY_SYS_RAMBUF_ADDR (K210_SRAM_START_ADDRESS+FIRMWARE_SRAM_SIZE) +// === SRAM area used for FreeRTOS #define MICRO_PY_FREE_RTOS_RESERVED (CONFIG_MICRO_PY_FREE_RTOS_RESERVED * 1024) - +#define FREE_RTOS_HEAP_START_ADDR (MICROPY_SYS_RAMBUF_ADDR + MYCROPY_SYS_RAMBUF_SIZE) #if MICROPY_K210_KPU_USED -/* - * !!! IMPORTANT !!! - * ====================================================================== - * When KPU memory is used to expand the FreeRTOS heap - * some variables (on task stack or on FreeRTOS heap) may be placed - * at SRAM address above 0x80600000 ! - * Those wariabled CAN'T be used in DMA transfers involving peripherals ! - * ====================================================================== - */ -#define MICROPY_SYS_RAMBUF_ADDR (K210_SRAM_START_ADDRESS+FIRMWARE_SRAM_SIZE) #define FREE_RTOS_TOTAL_HEAP_SIZE (K210_SRAM_SIZE - FIRMWARE_SRAM_SIZE - MYCROPY_SYS_RAMBUF_SIZE) -#define FREE_RTOS_HEAP_START_ADDR (MICROPY_SYS_RAMBUF_ADDR + MYCROPY_SYS_RAMBUF_SIZE) - #else -// KPU memory is NOT used -#define MICROPY_SYS_RAMBUF_ADDR (K210_SRAM_START_ADDRESS+FIRMWARE_SRAM_SIZE) #define FREE_RTOS_TOTAL_HEAP_SIZE (K210_SRAM_SIZE - FIRMWARE_SRAM_SIZE - MYCROPY_SYS_RAMBUF_SIZE + K210_AISRAM_SIZE) -#define FREE_RTOS_HEAP_START_ADDR (MICROPY_SYS_RAMBUF_ADDR + MYCROPY_SYS_RAMBUF_SIZE) #endif @@ -468,6 +469,7 @@ extern const struct _mp_print_t mp_debug_print; #define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) #define MICROPY_PY_BUILTINS_SLICE (1) #define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) +#define MICROPY_PY_BUILTINS_SLICE_INDICES (1) #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) #define MICROPY_PY_BUILTINS_ROUND_INT (1) #define MICROPY_PY_BUILTINS_TIMEOUTERROR (1) @@ -549,6 +551,11 @@ extern const struct _mp_print_t mp_debug_print; #else #define MICROPY_PY_USE_WIFI (0) #endif +#ifdef CONFIG_MICROPY_PY_USE_ESP32 +#define MICROPY_PY_USE_ESP32 (1) +#else +#define MICROPY_PY_USE_ESP32 (0) +#endif #if (MICROPY_PY_USE_WIFI == 1) || (MICROPY_PY_USE_GSM == 1) #define MICROPY_PY_USE_NETTWORK (1) diff --git a/k210-freertos/mpy_support/mphalport.c b/k210-freertos/mpy_support/mphalport.c index f6d96a9..8db8378 100755 --- a/k210-freertos/mpy_support/mphalport.c +++ b/k210-freertos/mpy_support/mphalport.c @@ -70,12 +70,16 @@ bool use_vm_hook = USE_MICROPY_VM_HOOK_LOOP; bool wdt_reset_in_vm_hook = false; task_ipc_t task_ipc = { 0 }; SemaphoreHandle_t inter_proc_mutex = NULL; -uint64_t sys_us_counter_cpu = 0; -uint64_t sys_us_counter = 0; uint32_t system_status = 0; +static uint64_t system_useconds = 0; +static uint64_t init_useconds = 0; +static uint64_t init_mcycles = 0; +static uint64_t system_cpu_frequency = (CPU_MAX_FREQ / 1000000); -uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { +//----------------------------------------------- +uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) +{ uintptr_t ret = 0; if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) { ret |= MP_STREAM_POLL_RD; @@ -96,31 +100,33 @@ mp_uint_t mp_hal_ticks_cpu(void) //----------------------------- mp_uint_t mp_hal_ticks_us(void) { - return ((read_csr64(mcycle) - sys_us_counter_cpu) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000)) + sys_us_counter; + system_useconds = (((read_csr64(mcycle)-init_mcycles) / system_cpu_frequency) + init_useconds); + return system_useconds; } -// Used for FreeRTOS syslog +// Used by FreeRTOS syslog //-------------------------- mp_uint_t sys_ticks_us(void) { - return ((read_csr64(mcycle) - sys_us_counter_cpu) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000)) + sys_us_counter; + system_useconds = (((read_csr64(mcycle)-init_mcycles) / system_cpu_frequency) + init_useconds); + return system_useconds; } //----------------------------- mp_uint_t mp_hal_ticks_ms(void) { - return mp_hal_ticks_us() / 1000; + system_useconds = (((read_csr64(mcycle)-init_mcycles) / system_cpu_frequency) + init_useconds); + return (system_useconds / 1000); } //------------------------------------------ void mp_hal_set_cpu_frequency(uint32_t freq) { - uint64_t count_us = mp_hal_ticks_us(); - sys_us_counter_cpu = read_csr64(mcycle); - sys_us_counter = count_us; - system_set_cpu_frequency(freq); - mp_hal_usdelay(1000); + system_cpu_frequency = CYCLES_PER_US; + init_mcycles = read_csr64(mcycle); + init_useconds = system_useconds; + mp_hal_usdelay(100); if (flash_spi > 0) { w25qxx_init(flash_spi, SPI_FF_QUAD, w25qxx_max_speed); } @@ -357,10 +363,9 @@ void mp_hal_wdt1_reset() //==================== void mp_hal_init(void) { - sys_us_counter = 0; - // Set the CPU clock mp_hal_set_cpu_frequency(mpy_config.config.cpu_clock); + system_cpu_frequency = CYCLES_PER_US; // Set the REPL uart baudrate and configure uarths uarths_baudrate = uarths_init(mpy_config.config.repl_bdr); @@ -620,43 +625,6 @@ void mp_hal_send_byte(char c) uarths_write_byte(c); } -//------------------------------------------------------- -uint16_t mp_hal_crc16(const uint8_t *buf, uint32_t count) -{ - uint16_t crc = 0xFFFF; - int i; - const uint8_t *pbuf = buf; - - while (count--) { - crc = crc ^ *pbuf++ << 8; - for (i=0; i<8; i++) { - if (crc & 0x8000) crc = crc << 1 ^ 0x1021; - else crc = crc << 1; - } - } - return crc; -} - -//------------------------------------------------------- -uint32_t mp_hal_crc32(const uint8_t *buf, uint32_t count) -{ - int32_t i, j; - uint32_t crc, mask; - const uint8_t *pbuf = buf; - - i = 0; - crc = 0xFFFFFFFF; - while (count--) { - crc = crc ^ (uint32_t)*pbuf++; - for (j = 7; j >= 0; j--) { - mask = -(crc & 1); - crc = (crc >> 1) ^ (0xEDB88320 & mask); - } - i = i + 1; - } - return ~crc; -} - //------------------------------------------------------- int32_t mp_hal_receive_byte(uint8_t *c, uint32_t timeout) { @@ -729,7 +697,7 @@ int mp_hal_get_file_block(uint8_t *buff, int size) crc_rec = (uint16_t)(buff[size] << 8); crc_rec |= (uint16_t)(buff[size+1] & 0xFF); - crc = mp_hal_crc16(buff, size); + crc = hal_crc16(buff, size, 0); // check crc if (crc == crc_rec) { res = 0; @@ -806,7 +774,7 @@ int mp_hal_send_file_block(uint8_t *buff, int size, bool docrc, int fsize) if (docrc) { // prepare crc - crc = mp_hal_crc16(buff, size); + crc = hal_crc16(buff, size, 0); buff[size] = (uint8_t)(crc >> 8); buff[size+1] = (uint8_t)(crc & 0xFF); } @@ -822,7 +790,7 @@ int mp_hal_send_file_block(uint8_t *buff, int size, bool docrc, int fsize) fs_buf[3] = (fsize >> 8) & 0xff; fs_buf[4] = (fsize >> 16) & 0xff; fs_buf[5] = (fsize >> 24) & 0xff; - crc = mp_hal_crc16(fs_buf, 6); + crc = hal_crc16(fs_buf, 6, 0); fs_buf[6] = (uint8_t)(crc >> 8); fs_buf[7] = (uint8_t)(crc & 0xFF); @@ -901,7 +869,9 @@ void mp_hal_usdelay(uint16_t us) { uint64_t start_us = mp_hal_ticks_us(); uint64_t end_us = start_us + us; - while (mp_hal_ticks_us() < end_us) {} + while (mp_hal_ticks_us() < end_us) { + ; + } } /* @@ -922,7 +892,9 @@ mp_uint_t _mp_hal_delay_us(mp_uint_t us) mp_uint_t end_us = start_us + us; if (us <= (portTICK_PERIOD_MS*2000)) { // For delays up to 2000 us we use blocking delay - while (mp_hal_ticks_us() < end_us) {} + while (mp_hal_ticks_us() < end_us) { + ; + } return us; } // Dont accept interrupt character while sleeping @@ -981,11 +953,3 @@ void mp_hal_delay_ms(mp_uint_t ms) { _mp_hal_delay_us(ms * 1000); } - -//-------------------------------------- -mp_uint_t _mp_hal_delay_ms(mp_uint_t ms) -{ - return _mp_hal_delay_us(ms * 1000); -} - - diff --git a/k210-freertos/mpy_support/mphalport.h b/k210-freertos/mpy_support/mphalport.h index 9010416..c3f00d2 100755 --- a/k210-freertos/mpy_support/mphalport.h +++ b/k210-freertos/mpy_support/mphalport.h @@ -30,6 +30,8 @@ #include "FreeRTOS.h" #include "task.h" #include "semphr.h" +#include "utility.h" + #include "py/ringbuf.h" #include "py/obj.h" #include "lib/utils/interrupt_char.h" @@ -63,13 +65,10 @@ typedef struct _task_ipc_t { bool irq; } __attribute__((aligned(8))) task_ipc_t; - extern task_ipc_t task_ipc; extern SemaphoreHandle_t inter_proc_mutex; extern mp_obj_t mpy2_task_callback; extern mp_obj_t main_task_callback; -extern uint64_t sys_us_counter_cpu; -extern uint64_t sys_us_counter; extern bool use_vm_hook; extern bool wdt_reset_in_vm_hook; extern uint32_t system_status; @@ -90,9 +89,6 @@ void mp_hal_wdt_reset(); void mp_hal_wtd1_enable(bool en, size_t tmo_ms); void mp_hal_wdt1_reset(); -uint16_t mp_hal_crc16(const uint8_t *buf, uint32_t count); -uint32_t mp_hal_crc32(const uint8_t *buf, uint32_t count); - int32_t mp_hal_receive_byte (unsigned char *c, uint32_t timeout); void mp_hal_send_bytes(char *buf, int len); void mp_hal_send_byte(char c); @@ -105,7 +101,6 @@ mp_uint_t mp_hal_ticks_ms(void); void mp_hal_usdelay(uint16_t us); mp_uint_t _mp_hal_delay_us(mp_uint_t us); -mp_uint_t _mp_hal_delay_ms(mp_uint_t ms); void mp_hal_delay_us(mp_uint_t us); void mp_hal_delay_ms(mp_uint_t ms); void mp_hal_init(void); diff --git a/k210-freertos/mpy_support/standard_lib/gsm/libGSM.c b/k210-freertos/mpy_support/standard_lib/gsm/libGSM.c index bfb8aa3..c8e3f6a 100644 --- a/k210-freertos/mpy_support/standard_lib/gsm/libGSM.c +++ b/k210-freertos/mpy_support/standard_lib/gsm/libGSM.c @@ -222,7 +222,7 @@ static GSM_Cmd *GSM_Init[] = #define GSM_InitCmdsSize (sizeof(GSM_Init)/sizeof(GSM_Cmd *)) -extern handle_t mp_rtc_rtc0; +//extern handle_t mp_rtc_rtc0; static void *ntp_time_cb = NULL; @@ -236,9 +236,6 @@ void set_rtc_time_from_seconds(time_t seconds) //rtc_set_datetime(mp_rtc_rtc0, tm_info); // set RTC time _set_sys_time(tm_info, 0); ntp_got_time = seconds; - if (sntp_enabled()) { - sntp_stop(); - } } //============================================== @@ -552,6 +549,9 @@ static void _handle_pppos_data(char *data) if (gsm_debug) LOGM(GSM_PPP_TAG, "NTP time synchronized (%lu)", ntp_got_time); if (ntp_time_cb) mp_sched_schedule((mp_obj_t)ntp_time_cb, mp_obj_new_int(ntp_got_time)); ntp_got_time = 0; + if (sntp_enabled()) { + sntp_stop(); + } } if (do_check) { diff --git a/k210-freertos/mpy_support/standard_lib/include/modmachine.h b/k210-freertos/mpy_support/standard_lib/include/modmachine.h index b7b75f2..4abd5b6 100755 --- a/k210-freertos/mpy_support/standard_lib/include/modmachine.h +++ b/k210-freertos/mpy_support/standard_lib/include/modmachine.h @@ -45,6 +45,7 @@ #define CPU_MAX_FREQ (PLL0_MAX_OUTPUT_FREQ / 2) #define KPU_MAX_FREQ (PLL1_MAX_OUTPUT_FREQ / 2) #define I2S_MAX_FREQ 0 +#define CYCLES_PER_US (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000) #define SYS_RESET_REASON_NONE 0 #define SYS_RESET_REASON_NLR 1 @@ -54,6 +55,14 @@ #define TIMER_MAX_TIMERS 12 +#define SPI_MASTER_0 0 +#define SPI_MASTER_1 1 +#define SPI_MASTER_WS2812_0 2 +#define SPI_MASTER_WS2812_1 3 +#define SPI_SLAVE 4 +#define SPI_INTERFACE_MAX 5 + + typedef enum _gpio_func_t { GPIO_FUNC_NONE, @@ -105,7 +114,8 @@ typedef enum _gpio_func_as_t GPIO_USEDAS_DVP_HREF, GPIO_USEDAS_DVP_PCLK, GPIO_USEDAS_DVP_SCLK, - GPIO_USEDAS_DVP_SDA + GPIO_USEDAS_DVP_SDA, + GPIO_USEDAS_HANDSHAKE } gpio_pin_func_as_t; @@ -184,6 +194,65 @@ typedef struct _machine_pwm_obj_t { } __attribute__((aligned(8))) machine_pwm_obj_t; +typedef union _ws2812b_rgb { + struct + { + uint32_t blue : 8; + uint32_t red : 8; + uint32_t green : 8; + uint32_t white : 8; + }; + uint32_t rgb; +} ws2812b_rgb; + +typedef struct _ws2812b_buffer_t +{ + size_t num_pix; + ws2812b_rgb *rgb_buffer; +} ws2812b_buffer_t; + +typedef struct _machine_hw_spi_obj_t { + mp_obj_base_t base; + int8_t spi_num; // SPI device used (0-1 spi master, 2-3 ws2812, 4 spi slave) + int8_t sck; + int8_t mosi; + int8_t miso; + int8_t cs; + int8_t handshake; + int8_t handshake_gpio; + int8_t mode; + int8_t firstbit; + int8_t nbits; + bool duplex; + bool reused_spi; + uint32_t baudrate; + uint32_t freq; + handle_t handle; // handle to SPI driver + handle_t spi_device; + uint8_t *slave_buffer; + uint32_t buffer_size; + uint32_t slave_ro_size; + bool slave_buffer_allocated; + mp_obj_t slave_cb; // slave callback function + TaskHandle_t slave_task; + QueueHandle_t slave_queue; + ws2812b_buffer_t ws2812_buffer; + uint16_t ws2812_lo; + uint16_t ws2812_hi; + uint32_t ws2812_rst; + uint16_t ws_lo; + uint16_t ws_hi; + uint32_t ws_rst; + uint32_t ws_needed_buf_size; + bool ws2812_white; + enum { + MACHINE_HW_SPI_STATE_NONE, + MACHINE_HW_SPI_STATE_INIT, + MACHINE_HW_SPI_STATE_DEINIT + } state; +} machine_hw_spi_obj_t; + + typedef struct _mpy_flash_config_t { uint32_t ver; bool use_two_main_tasks; @@ -227,6 +296,7 @@ extern const char *reset_reason[8]; extern const char *term_colors[8]; extern mpy_config_t mpy_config; extern void *mpy_timers_used[TIMER_MAX_TIMERS]; +extern QueueHandle_t spi_slave_task_queue; const char *term_color(enum term_colors_t color); bool mpy_config_crc(bool set); @@ -247,6 +317,8 @@ uint64_t random_at_most(uint32_t max); time_t _get_time(bool systm); void _set_sys_time(struct tm *tm_inf, int zone); +int spi_master_hard_init(uint8_t mosi, int8_t miso, uint8_t sck, int8_t cs, gpio_pin_func_t func); + extern const mp_obj_type_t machine_pin_type; extern const mp_obj_type_t machine_uart_type; extern const mp_obj_type_t machine_hw_i2c_type; diff --git a/k210-freertos/mpy_support/standard_lib/machine/machine_ow.c b/k210-freertos/mpy_support/standard_lib/machine/machine_ow.c index 20ef3d8..1f8e906 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/machine_ow.c +++ b/k210-freertos/mpy_support/standard_lib/machine/machine_ow.c @@ -120,6 +120,9 @@ STATIC mp_obj_t machine_onewire_make_new(const mp_obj_type_t *type, size_t n_arg mp_arg_val_t args[MP_ARRAY_SIZE(machine_neopixel_init_allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(machine_neopixel_init_allowed_args), machine_neopixel_init_allowed_args, args); + if (!machine_init_gpiohs()) { + mp_raise_ValueError("Cannot initialize gpiohs"); + } int wanted_pin = mp_obj_get_int(args[0].u_obj); diff --git a/k210-freertos/mpy_support/standard_lib/machine/machine_spi.c b/k210-freertos/mpy_support/standard_lib/machine/machine_spi.c index 506cd22..db7f559 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/machine_spi.c +++ b/k210-freertos/mpy_support/standard_lib/machine/machine_spi.c @@ -80,72 +80,15 @@ #include "modmachine.h" #include "mphalport.h" -#define SLAVE_BUFFER_MIN_SIZE 256 -#define SLAVE_BUFFER_MAX_SIZE (1024*1024) -#define SPI_MASTER_0 0 -#define SPI_MASTER_1 1 -#define SPI_MASTER_WS2812_0 2 -#define SPI_MASTER_WS2812_1 3 -#define SPI_SLAVE 4 - -#define SLAVE_TASK_REINIT 1001 -#define SLAVE_TASK_CALLBACK 1006 - -typedef union _ws2812b_rgb { - struct - { - uint32_t blue : 8; - uint32_t red : 8; - uint32_t green : 8; - uint32_t white : 8; - }; - uint32_t rgb; -} ws2812b_rgb; +#define SLAVE_BUFFER_MIN_SIZE 256 +#define SLAVE_BUFFER_MAX_SIZE (1024*1024) -typedef struct _ws2812b_buffer_t -{ - size_t num_pix; - ws2812b_rgb *rgb_buffer; -} ws2812b_buffer_t; - -typedef struct _machine_hw_spi_obj_t { - mp_obj_base_t base; - int8_t spi_num; // SPI device used (0-1 spi master, 2-3 ws2812, 4 spi slave) - int8_t sck; - int8_t mosi; - int8_t miso; - int8_t cs; - int8_t mode; - int8_t firstbit; - int8_t nbits; - bool duplex; - bool reused_spi; - uint32_t baudrate; - uint32_t freq; - handle_t handle; // handle to SPI driver - handle_t spi_device; - uint8_t *slave_buffer; - uint32_t buffer_size; - uint32_t slave_ro_size; - bool slave_buffer_allocated; - mp_obj_t slave_cb; // slave callback function - ws2812b_buffer_t ws2812_buffer; - uint16_t ws2812_lo; - uint16_t ws2812_hi; - uint32_t ws2812_rst; - uint16_t ws_lo; - uint16_t ws_hi; - uint32_t ws_rst; - uint32_t ws_needed_buf_size; - bool ws2812_white; - enum { - MACHINE_HW_SPI_STATE_NONE, - MACHINE_HW_SPI_STATE_INIT, - MACHINE_HW_SPI_STATE_DEINIT - } state; -} machine_hw_spi_obj_t; - -static const char *slave_err[10] = { +#define SLAVE_TASK_REINIT 1001 +#define SLAVE_TASK_CALLBACK 1006 + +#define SPI_SLAVE_MUTEX_WAIT_TIME 20 + +static const char *slave_err[12] = { "Ok", "Wrong command", "Cmd CSUM error", @@ -155,25 +98,27 @@ static const char *slave_err[10] = { "Timeout", "Error", "Fatal Error, SLAVE reset", + "Not 4-byte aligned", + "Memory error", "Unknown", }; -static const char *slave_commands[9] = { +static const char *slave_commands[10] = { "No command", - "Test", - "Read info", - "Status", - "Write data", - "Write data with csum", "Read data", - "Read data with csum", + "Write data", + "Read info", + "Write status", + "Write status&confirm", + "Read BUF state", + "ISR Read buffer", + "ISR Read confirmation", "Unknown", }; static const char *TAG = "[SPI]"; static machine_hw_spi_obj_t *slave_obj = NULL; -static TaskHandle_t slave_task = NULL; -static QueueHandle_t slave_task_queue = NULL; + static bool neopixel_show(machine_hw_spi_obj_t *self, bool test); @@ -231,8 +176,8 @@ STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_p self->mosi, self->miso, self->sck, self->cs); mp_printf(print, "\r\n (pin value of -1 means the pin is not used)"); - if (self->spi_num == SPI_SLAVE) mp_printf(print, "\r\n buffer_size=%u (%u read_only), callback: %s", - self->buffer_size, self->slave_ro_size, (self->slave_cb == mp_const_none) ? "False" : "True"); + if (self->spi_num == SPI_SLAVE) mp_printf(print, "\r\n buffer_size=%u (%u read_only), handshake=%d, callback: %s", + self->buffer_size, self->slave_ro_size, self->handshake, (self->slave_cb == mp_const_none) ? "False" : "True"); if ((self->spi_num == SPI_MASTER_WS2812_0) || (self->spi_num == SPI_MASTER_WS2812_1)) { mp_printf(print, "\r\n ws2812: pixels=%u, buffer size=%u (needs=%u)", self->ws2812_buffer.num_pix, self->buffer_size, self->ws_needed_buf_size); @@ -247,7 +192,7 @@ STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_p static bool spi_hard_deinit(machine_hw_spi_obj_t *self) { // Deconfigure used pins - mp_fpioa_cfg_item_t spi_pin_func[4]; + mp_fpioa_cfg_item_t spi_pin_func[5]; if (self->spi_num == SPI_SLAVE) { // === SPI slave int n_func = 3; @@ -258,6 +203,11 @@ static bool spi_hard_deinit(machine_hw_spi_obj_t *self) n_func = 4; spi_pin_func[3] = (mp_fpioa_cfg_item_t){-1, self->miso, GPIO_USEDAS_NONE, FUNC_RESV0}; } + if (self->handshake >= 0) { + gpiohs_set_free(self->handshake_gpio); + n_func = 5; + spi_pin_func[4] = (mp_fpioa_cfg_item_t){-1, self->handshake, GPIO_USEDAS_NONE, FUNC_RESV0}; + } fpioa_setup_pins(n_func, spi_pin_func); fpioa_freeused_pins(n_func, spi_pin_func); @@ -300,8 +250,8 @@ static bool spi_hard_deinit(machine_hw_spi_obj_t *self) return true; } -//------------------------------------------------------------------------------------------------------ -static int spi_master_hard_init(uint8_t mosi, int8_t miso, uint8_t sck, int8_t cs, gpio_pin_func_t func) +//----------------------------------------------------------------------------------------------- +int spi_master_hard_init(uint8_t mosi, int8_t miso, uint8_t sck, int8_t cs, gpio_pin_func_t func) { // mosi & sck are mandatory, miso & cs can be unused int spi_offset = 0, cs_offset = 0; @@ -467,24 +417,9 @@ STATIC void checkSPIws2812(machine_hw_spi_obj_t *self) } } -//------------------------------------------ -static int spi_slave_receive_hook(void *ctx) -{ - if (slave_task_queue) xQueueSend(slave_task_queue, ctx, 0); - return 0; -} - //-------------------------------------------- static void spi_slave_task(void *pvParameters) { - if (slave_task_queue == NULL) { - slave_task_queue = xQueueCreate( 8, sizeof(spi_slave_command_t) ); - if (slave_task_queue == NULL) { - LOGE("[SPI_SLAVE_TASK]", "Error creating message queue"); - slave_task = NULL; - vTaskDelete(NULL); - } - } TaskHandle_t task_handle = (TaskHandle_t)pvParameters; spi_slave_command_t slv_cmd = {0}; // if the task uses some MicroPython functions, we have to save @@ -493,56 +428,85 @@ static void spi_slave_task(void *pvParameters) vTaskSetThreadLocalStoragePointer(NULL, THREAD_LSP_ARGS, pvTaskGetThreadLocalStoragePointer(task_handle, THREAD_LSP_ARGS)); while (1) { + if (slave_obj->slave_queue == NULL) { + vTaskDelay(1000); + continue; + } // Check notification - if (xQueueReceive(slave_task_queue, &slv_cmd, 1000 / portTICK_RATE_MS) == pdTRUE) { + if (xQueueReceive(slave_obj->slave_queue, &slv_cmd, 1000 / portTICK_RATE_MS) == pdTRUE) { + if (slv_cmd.err == SPI_CMD_ERR_EXIT) { + // end task requested + break; + } if (slave_obj->state == MACHINE_HW_SPI_STATE_INIT) { - if (slv_cmd.err == SPI_CMD_ERR_FATAL) { + if ((slave_obj) && (slave_obj->slave_cb != mp_const_none)) { + // schedule callback function + mp_obj_t tuple[8]; + tuple[0] = mp_obj_new_int(slv_cmd.cmd); // command + tuple[1] = mp_obj_new_int(slv_cmd.opt); // command options or Master data type + tuple[2] = mp_obj_new_int(slv_cmd.err); // error code + tuple[3] = mp_obj_new_int(slv_cmd.addr); // buffer address + tuple[4] = mp_obj_new_int(slv_cmd.dummy_bytes); // number of dummy bytes + tuple[5] = mp_obj_new_int(slv_cmd.len); // transfer length + tuple[6] = mp_obj_new_int((slv_cmd.end_time - slv_cmd.start_time) / CYCLES_PER_US); // transfer time in us + tuple[7] = mp_obj_new_bytes((const byte *)slv_cmd.user_data, 12); // master data + + mp_sched_schedule(slave_obj->slave_cb, mp_obj_new_tuple(8, tuple)); + } + else { if (slv_cmd.cmd > SPI_CMD_MAX) slv_cmd.cmd = SPI_CMD_MAX; if (slv_cmd.err > SPI_CMD_ERR_MAX) slv_cmd.err = SPI_CMD_ERR_MAX; - LOGW("[SPI_SLAVE_TASK]", "SPI Slave fatal error, reseting"); - // spi slave unusable, needs to be reinitialized - // Deinit - if (slave_obj->spi_num == SPI_SLAVE) spi_slave_deinit(slave_obj->handle); - io_close(slave_obj->handle); - slave_obj->handle = 0; - spi_hard_deinit(slave_obj); - slave_obj->state = MACHINE_HW_SPI_STATE_NONE; - - // Initialize again - slave_obj->handle = io_open("/dev/spi_slave"); - if (slave_obj->handle == 0) { - LOGE("[SPI_SLAVE_TASK]", "Error reseting spi slave"); + + if ((slv_cmd.cmd == SPI_CMD_READ_TRANS) || (slv_cmd.cmd == SPI_CMD_STATUS_TRANS)) { + LOGD("[SPI_SLAVE]", "ISR Read: %d (%s)", slv_cmd.cmd, slave_commands[slv_cmd.cmd]); } - else { - if (spi_slave_hard_init(slave_obj->mosi, slave_obj->miso, slave_obj->sck, slave_obj->cs, GPIO_FUNC_SPI_SLAVE) != 0) { - LOGE("[SPI_SLAVE_TASK]", "Error reseting spi slave"); + else if (((slv_cmd.cmd == SPI_CMD_WRSTAT) || (slv_cmd.cmd == SPI_CMD_WRSTAT_CONFIRM)) && (slv_cmd.err == SPI_CMD_ERR_OK)) { + /* Command structure: + * ------------------------------------------------------------- + * 0 user data command code + * 1 user data command type (b0-b3) & dummy bytes (b4-b7) + * 2 - 13 user data (12 bytes) + * 14 - 15 16-bit crc + * ------------------------------------------------------------- + */ + char sstat[40] = {'\0'}; + if (slv_cmd.opt == 1) { + uint8_t key = slv_cmd.user_data[0]; + sprintf(sstat, "Keys:"); + if ((key & 1) == 0) strcat(sstat+5, " 1"); + key >>= 1; + if ((key & 1) == 0) strcat(sstat+5, " 2"); + key >>= 1; + if ((key & 1) == 0) strcat(sstat+5, " 3"); + key >>= 1; + if ((key & 1) == 0) strcat(sstat+5, " 4"); + } + else if (slv_cmd.opt == 2) { + sprintf(sstat, "U1=%u mV, U2=%u mV", *((uint16_t *)slv_cmd.user_data), *((uint16_t *)(slv_cmd.user_data+2))); } else { - spi_slave_config(slave_obj->handle, slave_obj->nbits, slave_obj->slave_buffer, slave_obj->buffer_size, slave_obj->slave_ro_size, - spi_slave_receive_hook, mp_hal_crc16, MICROPY_TASK_PRIORITY, slave_obj->mosi, slave_obj->miso); - slave_obj->state = MACHINE_HW_SPI_STATE_INIT; + for (int i=0; i<12; i++) { + sprintf(sstat+(i*3), "%02X ", slv_cmd.user_data[i]); + } + sstat[24] = '\0'; } - } - } - if (slave_obj->state == MACHINE_HW_SPI_STATE_INIT) { - if ((slave_obj) && (slave_obj->slave_cb != mp_const_none)) { - // schedule callback function - mp_obj_t tuple[4]; - tuple[0] = mp_obj_new_int(slv_cmd.cmd); - tuple[1] = mp_obj_new_int(slv_cmd.err); - tuple[2] = mp_obj_new_int(slv_cmd.addr); - tuple[3] = mp_obj_new_int(slv_cmd.len); - - mp_sched_schedule(slave_obj->slave_cb, mp_obj_new_tuple(4, tuple)); + LOGI("[SPI_SLAVE]", "Master status: %s", sstat); } else { - if (slv_cmd.err == SPI_CMD_ERR_OK) { - LOGD("[SPI_SLAVE]", "cmd=%u (%s), err=%u (%s), addr=%u, len=%u, time=%lu", - slv_cmd.cmd, slave_commands[slv_cmd.cmd], slv_cmd.err, slave_err[slv_cmd.err], slv_cmd.addr, slv_cmd.len, slv_cmd.time); - } - else { - LOGD("[SPI_SLAVE]", "err=%u (%s), time=%lu", slv_cmd.err, slave_err[slv_cmd.err], slv_cmd.time); - } + /* Command structure: + * ------------------ + * 0 command code & options + * 1 - 3 20-bit address & dummy bytes + * 4 - 5 16_bit length + * 6 - 13 user data (8 bytes) + * 14 - 15 16-bit crc + * ------------------- + */ + LOGD("[SPI_SLAVE]", "cmd=%u (%s%s%s), err=%u (%s), addr=%u, dummy=%u, len=%u, crc16=0x%04X, time=%lu ns (%lu ns)", + slv_cmd.cmd, slave_commands[slv_cmd.cmd], (slv_cmd.opt & 1) ? " crc" : "", (slv_cmd.opt & 2) ? " confirm" : "", + slv_cmd.err, slave_err[slv_cmd.err], slv_cmd.addr, slv_cmd.dummy_bytes, slv_cmd.len, slv_cmd.crc16, + ((slv_cmd.end_time - slv_cmd.start_time) * 1000) / CYCLES_PER_US, // total transfer time + ((slv_cmd.command_time - slv_cmd.start_time) * 1000) / CYCLES_PER_US ); // speed } } } @@ -550,14 +514,18 @@ static void spi_slave_task(void *pvParameters) } // task's main loop // Terminate task - slave_task = NULL; + if (slave_obj->slave_queue) { + vQueueDelete(slave_obj->slave_queue); + slave_obj->slave_queue = NULL; + } + slave_obj->slave_task = NULL; vTaskDelete(NULL); } //--------------------------------------------------------------------------------------------------------------- mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_id, ARG_baudrate, ARG_mode, ARG_polarity, ARG_phase, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso, ARG_cs, + enum { ARG_id, ARG_baudrate, ARG_mode, ARG_polarity, ARG_phase, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso, ARG_cs, ARG_handshake, ARG_duplex, ARG_bits, ARG_buffer, ARG_rolen, ARG_wsnum, ARG_wslo, ARG_wshi, ARG_wsrst, ARG_wswhite }; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_INT, {.u_int = 1} }, @@ -570,6 +538,7 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_handshake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_duplex, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, { MP_QSTR_slave_buffer, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, @@ -587,11 +556,16 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ machine_hw_spi_obj_t *self = m_new_obj(machine_hw_spi_obj_t); self->base.type = &machine_hw_spi_type; self->state = MACHINE_HW_SPI_STATE_NONE; + self->slave_queue = NULL; + self->slave_task = NULL; self->spi_num = args[ARG_id].u_int; - if ((self->spi_num < 0) || (self->spi_num > 4)) { + if ((self->spi_num < 0) || (self->spi_num >= SPI_INTERFACE_MAX)) { mp_raise_ValueError("Wrong SPI interface selected"); } + if ((self->spi_num == SPI_SLAVE) && (slave_obj != NULL)) { + mp_raise_ValueError("Only one SPI Slave instance can be created"); + } int mode = 0; if (args[ARG_mode].u_int < 0) { @@ -620,22 +594,23 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ if ((args[ARG_bits].u_int < 4) || (args[ARG_bits].u_int > 32)) { mp_raise_ValueError("SPI bits out of range (4 ~ 32)"); } - if ((self->spi_num == SPI_MASTER_WS2812_0) || (self->spi_num == SPI_MASTER_WS2812_1)) self->nbits = 32; - else self->nbits = args[ARG_bits].u_int; + else if (self->spi_num == SPI_SLAVE) self->nbits = 8; + else if (self->spi_num > SPI_MASTER_1) self->nbits = 32; + else self->nbits = args[ARG_bits].u_int & 0x3C; bool flag = true; if ((args[ARG_mosi].u_int < 0) || (args[ARG_mosi].u_int >= FPIOA_NUM_IO)) flag = false; else if (self->spi_num == SPI_SLAVE) { // in SLAVE mode cs, sck & mosi are required if ((args[ARG_sck].u_int < 0) || (args[ARG_sck].u_int >= FPIOA_NUM_IO)) flag = false; - else if ((args[ARG_cs].u_int < 0) || (args[ARG_cs].u_int >= FPIOA_NUM_IO)) flag = false; - else if ((args[ARG_miso].u_int < -1) || (args[ARG_miso].u_int >= FPIOA_NUM_IO)) flag = false; + if ((args[ARG_cs].u_int < 0) || (args[ARG_cs].u_int >= FPIOA_NUM_IO)) flag = false; + //if ((args[ARG_miso].u_int < -1) || (args[ARG_miso].u_int >= FPIOA_NUM_IO)) flag = false; } else if (self->spi_num <= SPI_MASTER_1) { // in MASTER mode sck & mosi are required if ((args[ARG_sck].u_int < 0) || (args[ARG_sck].u_int >= FPIOA_NUM_IO)) flag = false; - else if ((args[ARG_cs].u_int < -1) || (args[ARG_cs].u_int >= FPIOA_NUM_IO)) flag = false; - else if ((args[ARG_miso].u_int < -1) || (args[ARG_miso].u_int >= FPIOA_NUM_IO)) flag = false; + if ((args[ARG_cs].u_int < -1) || (args[ARG_cs].u_int >= FPIOA_NUM_IO)) flag = false; + if ((args[ARG_miso].u_int < -1) || (args[ARG_miso].u_int >= FPIOA_NUM_IO)) flag = false; } if (!flag) { mp_raise_ValueError("not all pins given or out of range"); @@ -671,7 +646,7 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ self->reused_spi = false; } if (!flag) { - mp_raise_ValueError("Error configuring SPI slave device"); + mp_raise_ValueError("Error configuring SPI device"); } // === SPI peripheral initialization === @@ -688,10 +663,11 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ self->duplex = args[ARG_duplex].u_bool; self->sck = args[ARG_sck].u_int; self->cs = args[ARG_cs].u_int; + self->handshake = args[ARG_handshake].u_int; self->slave_buffer = NULL; self->slave_cb = mp_const_none; if (args[ARG_rolen].u_int < 0) self->slave_ro_size = 0; - else self->slave_ro_size = args[ARG_rolen].u_int; + else self->slave_ro_size = args[ARG_rolen].u_int & 0xFFFFFFFC; self->ws2812_buffer.rgb_buffer = NULL; self->ws2812_hi = args[ARG_wshi].u_int; @@ -735,26 +711,47 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ } } else { - // SPI Slave - BaseType_t res = xTaskCreate( - spi_slave_task, // function entry - "spi_slave_task", // task name - configMINIMAL_STACK_SIZE, // stack_deepth - (void *)xTaskGetCurrentTaskHandle(), // function argument - MICROPY_TASK_PRIORITY+1, // task priority - &slave_task); // task handle - if (res != pdPASS) slave_task = NULL; - vTaskDelay(2); - if (slave_task == NULL) { - mp_raise_ValueError("error creating spi slave task"); + // ==== SPI Slave ==== + if (!machine_init_gpiohs()) { + mp_raise_ValueError("Cannot initialize gpiohs"); } + if (self->handshake >= 0) { + // Configure handshake pin + if (mp_used_pins[self->handshake].func != GPIO_FUNC_NONE) { + io_close(self->handle); + spi_hard_deinit(self); + mp_raise_ValueError(gpiohs_funcs_in_use[mp_used_pins[self->handshake].func]); + } + self->handshake_gpio = gpiohs_get_free(); + if (self->handshake_gpio < 0) { + io_close(self->handle); + spi_hard_deinit(self); + mp_raise_ValueError("Error configuring handshake pin"); + } + if (fpioa_set_function(self->handshake, FUNC_GPIOHS0 + self->handshake_gpio) < 0) { + gpiohs_set_free(self->handshake_gpio); + io_close(self->handle); + spi_hard_deinit(self); + mp_raise_ValueError("Error configuring handshake pin"); + } + gpio_set_drive_mode(gpiohs_handle, self->handshake_gpio, GPIO_DM_OUTPUT); + gpio_set_pin_value(gpiohs_handle, self->handshake_gpio, GPIO_PV_HIGH); + mp_used_pins[self->handshake].func = GPIO_FUNC_PIN; + mp_used_pins[self->handshake].usedas = GPIO_USEDAS_HANDSHAKE; + mp_used_pins[self->handshake].gpio = self->handshake_gpio; + mp_used_pins[self->handshake].fpioa_func = FUNC_GPIOHS0 + self->handshake_gpio; + } + else self->handshake_gpio = -1; self->freq = 0; self->duplex = false; if ((mp_obj_is_int(args[ARG_buffer].u_obj)) || (args[ARG_buffer].u_obj == mp_const_none)) { - if (args[ARG_buffer].u_obj == mp_const_none) self->buffer_size = 1024; - else self->buffer_size = mp_obj_get_int(args[ARG_buffer].u_obj); + if (args[ARG_buffer].u_obj == mp_const_none) self->buffer_size = 1024 * (self->nbits/8); + else self->buffer_size = mp_obj_get_int(args[ARG_buffer].u_obj) * (self->nbits/8); + if (self->buffer_size % 4) { + mp_raise_ValueError("SPI slave buffer size must be multiple of 4"); + } if ((self->buffer_size < SLAVE_BUFFER_MIN_SIZE) || (self->buffer_size > SLAVE_BUFFER_MAX_SIZE)) { io_close(self->handle); spi_hard_deinit(self); @@ -772,22 +769,66 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_ // MPy buffer object is provided mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW); - if (bufinfo.len < SLAVE_BUFFER_MIN_SIZE) { + if (bufinfo.len % 4) { + mp_raise_ValueError("SPI slave buffer size must be multiple of 4"); + } + if ((bufinfo.len < SLAVE_BUFFER_MIN_SIZE) || (bufinfo.len > SLAVE_BUFFER_MAX_SIZE)) { io_close(self->handle); spi_hard_deinit(self); mp_raise_ValueError("SPI slave buffer size out of range"); } - self->buffer_size = ((bufinfo.len * 8) / 8) - 8; + self->buffer_size = bufinfo.len - 8; self->slave_buffer = (uint8_t *)bufinfo.buf; self->slave_buffer_allocated = false; } if (self->slave_ro_size > (self->buffer_size / 2)) self->slave_ro_size = self->buffer_size / 2; memset(self->slave_buffer, 0, self->buffer_size); - spi_slave_config(self->handle, self->nbits, self->slave_buffer, self->buffer_size, self->slave_ro_size, - spi_slave_receive_hook, mp_hal_crc16, MICROPY_TASK_PRIORITY, self->mosi, self->miso); + + if (self->slave_queue == NULL) { + self->slave_queue = xQueueCreate( 8, sizeof(spi_slave_command_t) ); + if (self->slave_queue == NULL) { + io_close(self->handle); + spi_hard_deinit(self); + if ((self->slave_buffer_allocated) && (self->slave_buffer)) vPortFree(self->slave_buffer); + LOGE("[SPI_SLAVE_TASK]", "Error creating message queue"); + } + } slave_obj = self; + + BaseType_t res = xTaskCreate( + spi_slave_task, // function entry + "SpiSlave PyTask", // task name + configMINIMAL_STACK_SIZE, // stack_deepth + (void *)xTaskGetCurrentTaskHandle(), // function argument + MICROPY_TASK_PRIORITY+1, // task priority + &self->slave_task); // task handle + + if (res != pdPASS) self->slave_task = NULL; + vTaskDelay(2); + if (self->slave_task == NULL) { + io_close(self->handle); + spi_hard_deinit(self); + if ((self->slave_buffer_allocated) && (self->slave_buffer)) vPortFree(self->slave_buffer); + slave_obj = NULL; + mp_raise_ValueError("error creating spi slave task"); + } + + bool ret =spi_slave_config(self->handle, (void *)self->slave_buffer, self->buffer_size, self->slave_ro_size, + self->slave_queue, MICROPY_TASK_PRIORITY, self->mosi, self->miso, self->handshake_gpio); + if (!ret) { + spi_slave_command_t slv_cmd = {0}; + slv_cmd.err = SPI_CMD_ERR_EXIT; + xQueueSend(self->slave_queue, (void *)&slv_cmd, 0); // terminate task + io_close(self->handle); + spi_hard_deinit(self); + if ((self->slave_buffer_allocated) && (self->slave_buffer)) vPortFree(self->slave_buffer); + slave_obj = NULL; + mp_raise_ValueError("Error configuring spi slave driver"); + } + + LOGD(TAG, "Slave command length: %lu", sizeof(spi_slave_command_t)); } self->state = MACHINE_HW_SPI_STATE_INIT; @@ -865,7 +906,25 @@ STATIC mp_obj_t machine_hw_spi_deinit(mp_obj_t self_in) mp_raise_msg(&mp_type_OSError, "SPI not initialized"); } - if (self->spi_num == SPI_SLAVE) spi_slave_deinit(self->handle); + if (self->spi_num == SPI_SLAVE) { + spi_slave_deinit(self->handle); + // wait for slave task to stop; + int tmo = 5000; + while (self->slave_task != NULL) { + vTaskDelay(5); + tmo -= 5; + if (tmo == 0) { + vTaskDelete(self->slave_task); + self->slave_task = NULL; + if (self->slave_queue) { + vQueueDelete(self->slave_queue); + self->slave_queue = NULL; + } + LOGW(TAG, "Slave task forced to stop"); + break; + } + } + } io_close(self->handle); self->handle = 0; @@ -900,7 +959,7 @@ STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) } return mp_const_false; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); //-------------------------------------------------------------------------- STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) @@ -1065,38 +1124,66 @@ STATIC mp_obj_t mp_machine_spi_read_from_mem(mp_uint_t n_args, const mp_obj_t *p } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_machine_spi_read_from_mem_obj, 0, mp_machine_spi_read_from_mem); -//---------------------------------------------------------------------- -STATIC mp_obj_t _spi_slavecmd(uint8_t cmd, uint32_t addr, uint32_t size) +//---------------------------------------------------------------------------------------------------- +STATIC mp_obj_t mp_machine_spi_slavecmd(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - char buf[8]; + enum { ARG_cmd, ARG_addr, ARG_len, ARG_dummy, ARG_crc, ARG_confirm, ARG_data }; + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_cmd, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_len, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_dummy, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_crc, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_confirm, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args-1, pos_args+1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + machine_hw_spi_obj_t *self = pos_args[0]; + checkSPImaster(self); + + uint8_t cmd = (uint8_t)(args[ARG_cmd].u_int) & 0x07; + if (args[ARG_crc].u_bool) cmd |= 0x10; + if (args[ARG_confirm].u_bool) cmd |= 0x20; + uint32_t addr = (uint32_t)args[ARG_addr].u_int; + uint16_t len = (uint16_t)args[ARG_len].u_int; + bool has_data = false; + mp_buffer_info_t bufinfo; + if (mp_obj_is_type(args[ARG_data].u_obj, &mp_type_bytes)) { + mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); + if ((bufinfo.len < 1) || (bufinfo.len > 7)) { + mp_raise_ValueError("Wrong data size"); + } + has_data = true; + } + + char buf[16] = {0}; buf[0] = cmd; buf[1] = addr & 0xff; buf[2] = (addr >> 8) & 0xff; buf[3] = (addr >> 16) & 0xff; - buf[4] = size & 0xff; - buf[5] = (size >> 8) & 0xff; - buf[6] = (size >> 16) & 0xff; - buf[7] = 0; - for (int i=0; i<7; i++) { - buf[7] ^= buf[i]; - } - return mp_obj_new_str_of_type(&mp_type_bytes, (const byte*)buf, 8); -} -//-------------------------------------------------------------------------- -STATIC mp_obj_t mp_machine_spi_slavecmd(size_t n_args, const mp_obj_t *args) -{ - machine_hw_spi_obj_t *self = args[0]; - checkSPImaster(self); + buf[4] = len & 0xff; + buf[5] = (len >> 8) & 0xff; + buf[6] = (uint8_t)args[ARG_dummy].u_int; + if (has_data) { + memcpy(buf+7, bufinfo.buf, bufinfo.len); + } + uint16_t crc = hal_crc16((const void*)buf, 14, 0); + buf[14] = crc & 0xff; + buf[15] = (crc >> 8) & 0xff; - return _spi_slavecmd((uint8_t)mp_obj_get_int(args[1]), (uint32_t)mp_obj_get_int(args[2]), (uint32_t)mp_obj_get_int(args[3])); + return mp_obj_new_str_of_type(&mp_type_bytes, (const byte*)buf, 16); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_slavecmd_obj, 4, 4, mp_machine_spi_slavecmd); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_machine_spi_slavecmd_obj, 4, mp_machine_spi_slavecmd); -//------------------------------------------------------------------------ -static void _check_addr_len(machine_hw_spi_obj_t *self, int addr, int len) +//---------------------------------------------------------------------------------- +static void _check_addr_len(machine_hw_spi_obj_t *self, uint32_t addr, uint32_t len) { - if ((len < 1) || (len > self->buffer_size)) { + if (len > self->buffer_size) { mp_raise_ValueError("Length out of range"); } if (addr >= self->buffer_size) { @@ -1115,26 +1202,32 @@ STATIC mp_obj_t mp_machine_spi_slave_setdata(mp_obj_t self_in, mp_obj_t buf_in, mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); - int addr = mp_obj_get_int(addr_in); + uint32_t addr = mp_obj_get_int(addr_in); _check_addr_len(self, addr, bufinfo.len); - memcpy(self->slave_buffer + addr, bufinfo.buf, bufinfo.len); - return mp_const_none; + bool ret = spi_slave_set_buffer(self->handle, (uint8_t *)bufinfo.buf, addr, bufinfo.len); + + return (ret) ? mp_const_true : mp_const_false; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_slave_setdata_obj, mp_machine_spi_slave_setdata); -//-------------------------------------------------------------------------------- -STATIC mp_obj_t mp_machine_spi_slave_setbuffer(mp_obj_t self_in, mp_obj_t byte_in) +//------------------------------------------------------------------------------------ +STATIC mp_obj_t mp_machine_spi_slave_set_readbuffer(mp_obj_t self_in, mp_obj_t buf_in) { machine_hw_spi_obj_t *self = self_in; checkSPIslave(self); - uint8_t fill_byte = (uint8_t)mp_obj_get_int(byte_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != 16) { + mp_raise_ValueError("Read buffer size must be 16 bytes"); + } - memset(self->slave_buffer, fill_byte, self->buffer_size); - return mp_const_none; + bool ret = spi_slave_set_read_buffer(self->handle, (uint8_t *)bufinfo.buf); + + return (ret) ? mp_const_true : mp_const_false; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_slave_setbuffer_obj, mp_machine_spi_slave_setbuffer); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_slave_set_readbuffer_obj, mp_machine_spi_slave_set_readbuffer); //----------------------------------------------------------------------------------------------- STATIC mp_obj_t mp_machine_spi_slave_getdata(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t len_in) @@ -1142,8 +1235,8 @@ STATIC mp_obj_t mp_machine_spi_slave_getdata(mp_obj_t self_in, mp_obj_t addr_in, machine_hw_spi_obj_t *self = self_in; checkSPIslave(self); - int addr = mp_obj_get_int(addr_in); - int len = mp_obj_get_int(len_in); + uint32_t addr = mp_obj_get_int(addr_in); + uint32_t len = mp_obj_get_int(len_in); _check_addr_len(self, addr, len); uint8_t *databuf = pvPortMalloc(len); @@ -1151,16 +1244,37 @@ STATIC mp_obj_t mp_machine_spi_slave_getdata(mp_obj_t self_in, mp_obj_t addr_in, nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Error allocating data buffer")); } - mp_obj_t data; - memcpy(databuf, self->slave_buffer + addr, len); - data = mp_obj_new_bytes(databuf, len); + mp_obj_t data = mp_const_none; + + bool ret = spi_slave_get_buffer(self->handle, databuf, addr, len); + + if (ret) data = mp_obj_new_bytes(databuf, len); vPortFree(databuf); - // Return buffer data as byte array + return data; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_slave_getdata_obj, mp_machine_spi_slave_getdata); +//--------------------------------------------------------------------------------- +STATIC mp_obj_t mp_machine_spi_slave_setbuffer(size_t n_args, const mp_obj_t *args) +{ + machine_hw_spi_obj_t *self = args[0]; + checkSPIslave(self); + + uint8_t fill_byte = (uint8_t)mp_obj_get_int(args[1]); + uint32_t addr = 0; + if (n_args > 2) addr = (uint32_t)mp_obj_get_int(args[2]); + uint32_t len = self->buffer_size; + if (n_args > 3) len = (uint32_t)mp_obj_get_int(args[3]); + _check_addr_len(self, addr, len); + + bool ret = spi_slave_fill_buffer(self->handle, fill_byte, addr, len); + + return (ret) ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_slave_setbuffer_obj, 2, 4, mp_machine_spi_slave_setbuffer); + //---------------------------------------------------------------------------- STATIC mp_obj_t mp_machine_spi_slave_callback(mp_obj_t self_in, mp_obj_t func) { @@ -1177,6 +1291,22 @@ STATIC mp_obj_t mp_machine_spi_slave_callback(mp_obj_t self_in, mp_obj_t func) } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_slave_callback_obj, mp_machine_spi_slave_callback); +//-------------------------------------------------------------------------------- +STATIC mp_obj_t mp_machine_spi_slave_handshake(size_t n_args, const mp_obj_t *args) +{ + machine_hw_spi_obj_t *self = args[0]; + checkSPIslave(self); + + uint8_t type = 10; + if (n_args > 1) type = (uint8_t)mp_obj_get_int(args[1]); + + bool ret = spi_slave_set_handshake(self->handle, type); + + return (ret) ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_slave_handshake_obj, 1, 2, mp_machine_spi_slave_handshake); + + // ==== WS2812 functions ================================================================================= //-------------------------------------------------------------- @@ -1663,9 +1793,12 @@ STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { // Slave methods { MP_ROM_QSTR(MP_QSTR_setdata), (mp_obj_t)&mp_machine_spi_slave_setdata_obj }, + { MP_ROM_QSTR(MP_QSTR_setReadBuf), (mp_obj_t)&mp_machine_spi_slave_set_readbuffer_obj }, { MP_ROM_QSTR(MP_QSTR_fillbuffer), (mp_obj_t)&mp_machine_spi_slave_setbuffer_obj }, { MP_ROM_QSTR(MP_QSTR_getdata), (mp_obj_t)&mp_machine_spi_slave_getdata_obj }, { MP_ROM_QSTR(MP_QSTR_callback), (mp_obj_t)&mp_machine_spi_slave_callback_obj }, + { MP_ROM_QSTR(MP_QSTR_handshake), (mp_obj_t)&mp_machine_spi_slave_handshake_obj }, + { MP_ROM_QSTR(MP_QSTR_hs), (mp_obj_t)&mp_machine_spi_slave_handshake_obj }, // WS2812 methods { MP_ROM_QSTR(MP_QSTR_ws_clear), (mp_obj_t)&machine_neopixel_clear_obj }, @@ -1686,13 +1819,9 @@ STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_WS2812_1), MP_ROM_INT(SPI_MASTER_WS2812_1) }, { MP_ROM_QSTR(MP_QSTR_SPI_SLAVE), MP_ROM_INT(SPI_SLAVE) }, - { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_TEST), MP_ROM_INT(SPI_CMD_TEST_COMMAND) }, - { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_INFO), MP_ROM_INT(SPI_CMD_READ_INFO) }, - { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_STATUS), MP_ROM_INT(SPI_CMD_LAST_STATUS) }, - { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_WRITE), MP_ROM_INT(SPI_CMD_WRITE_DATA_BLOCK) }, - { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_WRITE_CSUM),MP_ROM_INT(SPI_CMD_WRITE_DATA_BLOCK_CSUM) }, { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_READ), MP_ROM_INT(SPI_CMD_READ_DATA_BLOCK) }, - { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_READ_CSUM), MP_ROM_INT(SPI_CMD_READ_DATA_BLOCK_CSUM) }, + { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_WRITE), MP_ROM_INT(SPI_CMD_WRITE_DATA_BLOCK) }, + { MP_ROM_QSTR(MP_QSTR_SLAVE_CMD_INFO), MP_ROM_INT(SPI_CMD_READ_INFO) }, { MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(0x00000000) }, { MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(0x00FFFFFF) }, diff --git a/k210-freertos/mpy_support/standard_lib/machine/machine_uart.c b/k210-freertos/mpy_support/standard_lib/machine/machine_uart.c index cfd093a..37dd177 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/machine_uart.c +++ b/k210-freertos/mpy_support/standard_lib/machine/machine_uart.c @@ -56,8 +56,6 @@ typedef struct _task_params_t { void *thread_handle; } task_params_t; -static task_params_t task_params; - static const char *_parity_name[] = {"None", "Odd", "Even"}; static const char *_stopbits_name[] = {"1", "1.5", "2"}; @@ -606,6 +604,7 @@ static void _sched_callback(mp_obj_t function, int uart, int type, int iarglen, //--------------------------------------------- static void uart_event_task(void *pvParameters) { + LOGD(TAG, "UART task started"); task_params_t *task_params = (task_params_t *)pvParameters; // if the task uses some MicroPython functions, we have to save // MicroPython state in local storage pointers @@ -660,6 +659,7 @@ static void uart_event_task(void *pvParameters) } // Terminate task + LOGD(TAG, "UART task terminated"); xSemaphoreTake(mpy_uarts[self->uart_num].uart_mutex, UART_MUTEX_TIMEOUT); mpy_uarts[self->uart_num].task_id = NULL; xSemaphoreGive(mpy_uarts[self->uart_num].uart_mutex); @@ -1013,6 +1013,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args); //Create a task to handle UART receiving from uart ISR + task_params_t task_params; task_params.uart_obj = (void *)self; task_params.thread_handle = xTaskGetCurrentTaskHandle(); if (mpy_uarts[self->uart_num].task_id == 0) { @@ -1020,7 +1021,7 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, uart_event_task, // function entry "uart_event_task", // task name configMINIMAL_STACK_SIZE, // stack_deepth - (void *)self, // function argument + (void *)&task_params, // function argument MICROPY_TASK_PRIORITY, // task priority &mpy_uarts[self->uart_num].task_id); // task handle if (res != pdPASS) { diff --git a/k210-freertos/mpy_support/standard_lib/machine/modmachine.c b/k210-freertos/mpy_support/standard_lib/machine/modmachine.c index d7e99f8..6cf8b23 100755 --- a/k210-freertos/mpy_support/standard_lib/machine/modmachine.c +++ b/k210-freertos/mpy_support/standard_lib/machine/modmachine.c @@ -98,7 +98,7 @@ const char *gpiohs_funcs_in_use[17] = { "pin used by DVP", }; -const char *gpiohs_usedas[29] = { +const char *gpiohs_usedas[30] = { "--", "Tx", "Rx", @@ -128,6 +128,7 @@ const char *gpiohs_usedas[29] = { "dvp_pclk", "dvp_sclk", "dvp_sda", + "handshake", }; const char *reset_reason[8] = { @@ -171,7 +172,7 @@ const char *term_color(enum term_colors_t color) //--------------------------- bool mpy_config_crc(bool set) { - uint32_t ccrc = mp_hal_crc32((const uint8_t *)&mpy_config.config, sizeof(mpy_flash_config_t)); + uint32_t ccrc = hal_crc32((const void *)&mpy_config.config, sizeof(mpy_flash_config_t), 0); if (set) { mpy_config.crc = ccrc; int res = w25qxx_write_data(MICRO_PY_FLASH_CONFIG_START, (uint8_t *)&mpy_config, sizeof(mpy_config_t)); @@ -189,7 +190,7 @@ bool mpy_read_config() // read config from flash int res = w25qxx_read_data(MICRO_PY_FLASH_CONFIG_START, (uint8_t *)&config, sizeof(mpy_config_t)); if (res == W25QXX_OK) { - uint32_t ccrc = mp_hal_crc32((const uint8_t *)&config.config, sizeof(mpy_flash_config_t)); + uint32_t ccrc = hal_crc32((const void *)&config.config, sizeof(mpy_flash_config_t), 0); if (config.crc == ccrc) { if (config.config.ver == MICROPY_PY_LOBO_VERSION_NUM) { // read config's crc ok, copy to current config @@ -437,27 +438,47 @@ STATIC mp_obj_t mod_machine_log_level(mp_obj_t level_in) } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_machine_log_level_obj, mod_machine_log_level); -//------------------------------------------------ -STATIC mp_obj_t mod_machine_crc16(mp_obj_t buf_in) +//------------------------------------------------------------------- +STATIC mp_obj_t mod_machine_crc8(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + uint8_t previousCrc8 = 0; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + if (n_args > 1) previousCrc8 = (uint8_t)mp_obj_get_int(args[1]); + + uint8_t crc = hal_crc8((uint8_t *)bufinfo.buf, bufinfo.len, previousCrc8); - uint16_t crc = mp_hal_crc16((uint8_t *)bufinfo.buf, bufinfo.len); return mp_obj_new_int(crc); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_machine_crc16_obj, mod_machine_crc16); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_machine_crc8_obj, 1, 2, mod_machine_crc8); -//------------------------------------------------ -STATIC mp_obj_t mod_machine_crc32(mp_obj_t buf_in) +//-------------------------------------------------------------------- +STATIC mp_obj_t mod_machine_crc16(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + uint16_t previousCrc16 = 0; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + if (n_args > 1) previousCrc16 = (uint16_t)mp_obj_get_int(args[1]); + + uint16_t crc = hal_crc16((uint8_t *)bufinfo.buf, bufinfo.len, previousCrc16); - uint32_t crc = mp_hal_crc32((uint8_t *)bufinfo.buf, bufinfo.len); return mp_obj_new_int(crc); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_machine_crc32_obj, mod_machine_crc32); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_machine_crc16_obj, 1, 2, mod_machine_crc16); + +//-------------------------------------------------------------------- +STATIC mp_obj_t mod_machine_crc32(size_t n_args, const mp_obj_t *args) +{ + mp_buffer_info_t bufinfo; + uint32_t previousCrc32 = 0; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + if (n_args > 1) previousCrc32 = (uint32_t)mp_obj_get_int(args[1]); + + uint32_t crc = hal_crc32((const void *)bufinfo.buf, bufinfo.len, previousCrc32); + + return mp_obj_new_int(crc); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_machine_crc32_obj, 1, 2, mod_machine_crc32); //------------------------------------------------- STATIC mp_obj_t mod_machine_base64(mp_obj_t buf_in) @@ -978,6 +999,23 @@ STATIC mp_obj_t machine_flashSpeed(size_t n_args, const mp_obj_t *args) STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_flashSpeed_obj, 0, 1, machine_flashSpeed); +extern uint32_t SPI_TRANSMISSION_THRESHOLD; +//-------------------------------------------------------------------- +STATIC mp_obj_t machine_spiTreshold(size_t n_args, const mp_obj_t *args) +{ + if (n_args > 0) { + int spitresh = (uint32_t)mp_obj_get_int(args[0]); + if ((spitresh < 0) || (spitresh > 10000000)) { + mp_raise_ValueError("Allowed values: 0 ~ 10000000"); + } + SPI_TRANSMISSION_THRESHOLD = spitresh; + } + + return mp_obj_new_int(SPI_TRANSMISSION_THRESHOLD); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_spiTreshold_obj, 0, 1, machine_spiTreshold); + + //=========================================================== STATIC const mp_map_elem_t machine_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_machine) }, @@ -997,6 +1035,7 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_reset_reason), MP_ROM_PTR(&mod_machine_reset_reason_obj) }, { MP_ROM_QSTR(MP_QSTR_pinstat), MP_ROM_PTR(&machine_pinstat_obj) }, { MP_ROM_QSTR(MP_QSTR_loglevel), MP_ROM_PTR(&mod_machine_log_level_obj) }, + { MP_ROM_QSTR(MP_QSTR_crc8), MP_ROM_PTR(&mod_machine_crc8_obj) }, { MP_ROM_QSTR(MP_QSTR_crc16), MP_ROM_PTR(&mod_machine_crc16_obj) }, { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_machine_crc32_obj) }, { MP_ROM_QSTR(MP_QSTR_base64enc), MP_ROM_PTR(&mod_machine_base64_obj) }, @@ -1014,6 +1053,7 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_k210_id), MP_ROM_PTR(&mod_machine_K210serial_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_serial), MP_ROM_PTR(&mod_machine_FlashSerial_obj) }, { MP_ROM_QSTR(MP_QSTR_flash_speed), MP_ROM_PTR(&machine_flashSpeed_obj) }, + { MP_ROM_QSTR(MP_QSTR_spiTreshold), MP_ROM_PTR(&machine_spiTreshold_obj) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) }, diff --git a/k210-freertos/mpy_support/standard_lib/machine/modtest.c b/k210-freertos/mpy_support/standard_lib/machine/modtest.c index 202266a..a3f77c1 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/modtest.c +++ b/k210-freertos/mpy_support/standard_lib/machine/modtest.c @@ -99,8 +99,6 @@ STATIC mp_obj_t test_flash(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw sysctl_pll_set_freq(SYSCTL_PLL0, pll0); mp_hal_set_cpu_frequency(cpufreq); uint64_t count_us = mp_hal_ticks_us(); - sys_us_counter_cpu = read_csr64(mcycle); - sys_us_counter = count_us; uarths_init(uarths_baudrate); } @@ -279,8 +277,6 @@ STATIC mp_obj_t test_flash(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw sysctl_pll_set_freq(SYSCTL_PLL0, old_pll0); mp_hal_set_cpu_frequency(old_cpufreq); uint64_t count_us = mp_hal_ticks_us(); - sys_us_counter_cpu = read_csr64(mcycle); - sys_us_counter = count_us; uarths_init(uarths_baudrate); vTaskDelay(10); } diff --git a/k210-freertos/mpy_support/standard_lib/machine/modymodem.c b/k210-freertos/mpy_support/standard_lib/machine/modymodem.c index b1e9760..e2c78d5 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/modymodem.c +++ b/k210-freertos/mpy_support/standard_lib/machine/modymodem.c @@ -171,7 +171,7 @@ static int32_t Receive_Packet (uint8_t *data, int *length, uint32_t timeout) *length = -2; return 0; } - if (mp_hal_crc16(&data[PACKET_HEADER], packet_size + PACKET_TRAILER) != 0) { + if (hal_crc16(&data[PACKET_HEADER], packet_size + PACKET_TRAILER, 0) != 0) { *length = -2; return 0; } @@ -371,7 +371,7 @@ static void Ymodem_PrepareIntialPacket(uint8_t *data, char *fileName, uint32_t l 1 + strlen((char *)(data + PACKET_HEADER + strlen((char *)(data+PACKET_HEADER)) + 1))] = ' '; // add crc - tempCRC = mp_hal_crc16(&data[PACKET_HEADER], PACKET_SIZE); + tempCRC = hal_crc16(&data[PACKET_HEADER], PACKET_SIZE, 0); data[PACKET_SIZE + PACKET_HEADER] = tempCRC >> 8; data[PACKET_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF; } @@ -385,7 +385,7 @@ static void Ymodem_PrepareLastPacket(uint8_t *data) data[0] = SOH; data[1] = 0x00; data[2] = 0xff; - tempCRC = mp_hal_crc16(&data[PACKET_HEADER], PACKET_SIZE); + tempCRC = hal_crc16(&data[PACKET_HEADER], PACKET_SIZE, 0); //tempCRC = crc16_le(0, &data[PACKET_HEADER], PACKET_SIZE); data[PACKET_SIZE + PACKET_HEADER] = tempCRC >> 8; data[PACKET_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF; @@ -413,8 +413,8 @@ static void Ymodem_PreparePacket(uint8_t *data, uint8_t pktNo, uint32_t sizeBlk, data[i] = 0x00; // EOF (0x1A) or 0x00 } } - tempCRC = mp_hal_crc16(&data[PACKET_HEADER], PACKET_1K_SIZE); - //tempCRC = crc16_le(0, &data[PACKET_HEADER], PACKET_1K_SIZE); + tempCRC = hal_crc16(&data[PACKET_HEADER], PACKET_1K_SIZE, 0); + //tempCRC = crc16_le(0, &data[PACKET_HEADER], PACKET_1K_SIZE, 0); data[PACKET_1K_SIZE + PACKET_HEADER] = tempCRC >> 8; data[PACKET_1K_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF; } diff --git a/k210-freertos/mpy_support/standard_lib/machine/ow/owb.c b/k210-freertos/mpy_support/standard_lib/machine/ow/owb.c index 8efe652..3a4c98f 100644 --- a/k210-freertos/mpy_support/standard_lib/machine/ow/owb.c +++ b/k210-freertos/mpy_support/standard_lib/machine/ow/owb.c @@ -39,6 +39,7 @@ #include "FreeRTOS.h" #include "task.h" #include "syslog.h" +#include "utility.h" #include "owb.h" @@ -66,48 +67,6 @@ static bool _is_init(const OneWireBus * bus) return ok; } -/** - * @brief 1-Wire 8-bit CRC lookup. - * @param[in] crc Starting CRC value. Pass in prior CRC to accumulate. - * @param[in] data Byte to feed into CRC. - * @return Resultant CRC value. - */ -static uint8_t _calc_crc(uint8_t crc, uint8_t data) -{ - // https://www.maximintegrated.com/en/app-notes/index.mvp/id/27 - static const uint8_t table[256] = { - 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, - 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, - 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, - 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, - 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, - 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, - 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, - 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, - 140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205, - 17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80, - 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238, - 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, - 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, - 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, - 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, - 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 - }; - - return table[crc ^ data]; -} - -static uint8_t _calc_crc_block(uint8_t crc, const uint8_t * buffer, size_t len) -{ - do - { - crc = _calc_crc(crc, *buffer++); - LOGD(TAG, "crc 0x%02x, len %d", (int)crc, (int)len); - } - while (--len > 0); - return crc; -} - /** * @param[out] is_found true if a device was found, false if not * @return status @@ -496,14 +455,20 @@ owb_status owb_write_rom_code(const OneWireBus * bus, OneWireBus_ROMCode rom_cod return status; } +/** + * @brief 1-Wire 8-bit CRC lookup. + * @param[in] crc Starting CRC value. Pass in prior CRC to accumulate. + * @param[in] data Byte to feed into CRC. + * @return Resultant CRC value. + */ uint8_t owb_crc8_byte(uint8_t crc, uint8_t data) { - return _calc_crc(crc, data); + return Crc8LookupTable[crc ^ data]; } uint8_t owb_crc8_bytes(uint8_t crc, const uint8_t * data, size_t len) { - return _calc_crc_block(crc, data, len); + return hal_crc8(data, len, crc); } owb_status owb_search_first(const OneWireBus * bus, OneWireBus_SearchState * state, bool* found_device) diff --git a/k210-freertos/mpy_support/standard_lib/mqtt/http_client.c b/k210-freertos/mpy_support/standard_lib/mqtt/http_client.c index 063960d..b0beb3e 100644 --- a/k210-freertos/mpy_support/standard_lib/mqtt/http_client.c +++ b/k210-freertos/mpy_support/standard_lib/mqtt/http_client.c @@ -127,7 +127,7 @@ static const char *DEFAULT_HTTP_USER_AGENT = "MicroPython HTTP Client/1.0"; static const char *DEFAULT_HTTP_PROTOCOL = "HTTP/1.1"; static const char *DEFAULT_HTTP_PATH = "/"; static int DEFAULT_MAX_REDIRECT = 10; -static int DEFAULT_TIMEOUT_MS = 2500; +static int DEFAULT_TIMEOUT_MS = 5000; static const char *HTTP_METHOD_MAPPING[] = { "GET", @@ -460,23 +460,21 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co return NULL; } - if ((net_active_interfaces & ACTIVE_INTERFACE_WIFI)) { - transport_handle_t ssl; - _success = ( - (ssl = transport_ssl_init()) && - (transport_set_default_port(ssl, DEFAULT_HTTPS_PORT) == 0) && - (transport_list_add(client->transport_list, ssl, "https") == 0) - ); - - if (!_success) { - if (transport_debug) LOGE(TAG, "Error initialize SSL Transport"); - esp_http_client_cleanup(client); - return NULL; - } + transport_handle_t ssl; + _success = ( + (ssl = transport_ssl_init()) && + (transport_set_default_port(ssl, DEFAULT_HTTPS_PORT) == 0) && + (transport_list_add(client->transport_list, ssl, "https") == 0) + ); - if (config->cert_pem) { - transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); - } + if (!_success) { + if (transport_debug) LOGE(TAG, "Error initialize SSL Transport"); + esp_http_client_cleanup(client); + return NULL; + } + + if (config->cert_pem) { + transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); } diff --git a/k210-freertos/mpy_support/standard_lib/mqtt/mqtt_client.c b/k210-freertos/mpy_support/standard_lib/mqtt/mqtt_client.c index aaf4ca8..ed6bf7b 100644 --- a/k210-freertos/mpy_support/standard_lib/mqtt/mqtt_client.c +++ b/k210-freertos/mpy_support/standard_lib/mqtt/mqtt_client.c @@ -269,39 +269,36 @@ esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *co } else if (config->transport == MQTT_TRANSPORT_OVER_WS) goto _mqtt_init_failed; - if ((net_active_interfaces & ACTIVE_INTERFACE_WIFI)) { - transport_handle_t ssl = transport_ssl_init(); - if (ssl) { - transport_set_default_port(ssl, MQTT_SSL_DEFAULT_PORT); - if (config->cert_pem) { - transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); - } - if (config->client_cert_pem) { - transport_ssl_set_client_cert_data(ssl, config->client_cert_pem, strlen(config->client_cert_pem)); - } - if (config->client_key_pem) { - transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem)); - } - transport_list_add(client->transport_list, ssl, "mqtts"); - if (config->transport == MQTT_TRANSPORT_OVER_SSL) { - client->config->scheme = create_string("mqtts", 5); - K210_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed); - } + transport_handle_t ssl = transport_ssl_init(); + if (ssl) { + transport_set_default_port(ssl, MQTT_SSL_DEFAULT_PORT); + if (config->cert_pem) { + transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem)); } - else if (config->transport == MQTT_TRANSPORT_OVER_SSL) goto _mqtt_init_failed; - - transport_handle_t wss = transport_ws_init(ssl); - if (wss) { - transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT); - transport_list_add(client->transport_list, wss, "wss"); - if (config->transport == MQTT_TRANSPORT_OVER_WSS) { - client->config->scheme = create_string("wss", 3); - K210_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed); - } + if (config->client_cert_pem) { + transport_ssl_set_client_cert_data(ssl, config->client_cert_pem, strlen(config->client_cert_pem)); + } + if (config->client_key_pem) { + transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem)); + } + transport_list_add(client->transport_list, ssl, "mqtts"); + if (config->transport == MQTT_TRANSPORT_OVER_SSL) { + client->config->scheme = create_string("mqtts", 5); + K210_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed); + } + } + else if (config->transport == MQTT_TRANSPORT_OVER_SSL) goto _mqtt_init_failed; + + transport_handle_t wss = transport_ws_init(ssl); + if (wss) { + transport_set_default_port(wss, MQTT_WSS_DEFAULT_PORT); + transport_list_add(client->transport_list, wss, "wss"); + if (config->transport == MQTT_TRANSPORT_OVER_WSS) { + client->config->scheme = create_string("wss", 3); + K210_MEM_CHECK(MQTT_TAG, client->config->scheme, goto _mqtt_init_failed); } - else if (config->transport == MQTT_TRANSPORT_OVER_WSS) goto _mqtt_init_failed; } - else if ((config->transport == MQTT_TRANSPORT_OVER_WSS) || (config->transport == MQTT_TRANSPORT_OVER_WSS)) goto _mqtt_init_failed; + else if (config->transport == MQTT_TRANSPORT_OVER_WSS) goto _mqtt_init_failed; if (client->config->uri) { if (esp_mqtt_client_set_uri(client, client->config->uri) != 0) { diff --git a/k210-freertos/mpy_support/standard_lib/mqtt/transport_ssl.c b/k210-freertos/mpy_support/standard_lib/mqtt/transport_ssl.c index 0df1db8..cf211a5 100644 --- a/k210-freertos/mpy_support/standard_lib/mqtt/transport_ssl.c +++ b/k210-freertos/mpy_support/standard_lib/mqtt/transport_ssl.c @@ -21,78 +21,242 @@ #include "transport.h" #include "transport_ssl.h" +#include "lwip/sockets.h" +#include "lwip/dns.h" +#include "lwip/netdb.h" + +#include "mbedtls/platform.h" +#include "mbedtls/ssl.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/pk.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/debug.h" +#include "mbedtls/net_sockets.h" static const char *TAG = "TRANS_SSL"; +#ifdef MBEDTLS_DEBUG_C +static void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { + (void)ctx; + if (!transport_debug) return; + char *pfile = strrchr(file, '/'); + if (!pfile) { + LOGM("[mbedtls]", "[%d] %s:%04d: %s", level, file, line, str); + } + pfile += 1; + if (level == 1) LOGE("[mbedtls]", "[%d] %s:%04d: %s", level, pfile, line, str); + else if (level == 2) LOGW("[mbedtls]", "[%d] %s:%04d: %s", level, pfile, line, str); + else if (level == 3) LOGI("[mbedtls]", "[%d] %s:%04d: %s", level, pfile, line, str); + else if (level == 4) LOGD("[mbedtls]", "[%d] %s:%04d: %s", level, pfile, line, str); +} +#endif + + /* * WiFi SSL specific transport data */ typedef struct { - socket_obj_t *sock; - void *cert_pem_data; - int cert_pem_len; - /* - void *client_cert_pem_data; - int client_cert_pem_len; - void *client_key_pem_data; - int client_key_pem_len; - bool mutual_authentication; - bool ssl_initialized; - bool verify_server; - */ + socket_obj_t *sock; + void *cert_pem_data; + int cert_pem_len; + // used only with lwip + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ctx; + mbedtls_x509_crt cacert; + mbedtls_x509_crt client_cert; + mbedtls_pk_context client_key; + mbedtls_ssl_config conf; + mbedtls_net_context client_fd; + void *client_cert_pem_data; + int client_cert_pem_len; + void *client_key_pem_data; + int client_key_pem_len; + bool mutual_authentication; + bool ssl_initialized; + bool verify_server; } transport_ssl_t; static int ssl_close(transport_handle_t t); -#if MICROPY_PY_USE_WIFI //-------------------------------------------------------------------------------------- static int ssl_connect(transport_handle_t t, const char *host, int port, int timeout_ms) { int ret = -1; transport_ssl_t *ssl = transport_get_context_data(t); - if (!ssl) return -1; - if (ssl->cert_pem_data) { - ret = wifi_sendcertificate((const char *)ssl->cert_pem_data, ssl->cert_pem_len); - if (ret < 0) { - if (transport_debug) LOGE(TAG, "error loading CA certificate %d", ret); + if (net_active_interfaces & ACTIVE_INTERFACE_WIFI) { + #if MICROPY_PY_USE_WIFI + + if (ssl->cert_pem_data) { + ret = wifi_sendcertificate((const char *)ssl->cert_pem_data, ssl->cert_pem_len); + if (ret < 0) { + if (transport_debug) LOGE(TAG, "error loading CA certificate %d", ret); + goto wexit; + } + } + else { + } + + ret = -1; + /* + if (ssl->client_cert_pem_data && ssl->client_key_pem_data) { + if (transport_debug) LOGW(TAG, "Client cert/key authentication not available"); + } + else if (ssl->client_cert_pem_data || ssl->client_key_pem_data) { + if (transport_debug) LOGE(TAG, "You have to provide both client_cert_pem and client_key_pem for mutual authentication"); goto exit; } + */ + + ssl->sock->fd = at_get_socket(ssl->sock); + if (ssl->sock->fd < 0) { + vPortFree(ssl); + if (transport_debug) LOGE(TAG, "Error creating socket"); + goto wexit; + } + ssl->sock->link_id = ssl->sock->fd; + if (transport_debug) LOGI(TAG, "Socket created: %d", ssl->sock->fd); + + #if MICROPY_PY_USE_WIFI + ret = wifi_connect(ssl->sock, host, port, 0); + #endif + if (ret < 0) { + if (transport_debug) LOGE(TAG, "error connecting %d", ret); + goto wexit; + } + if (transport_debug) LOGD(TAG, "Connected to %s:%d", host, port); + ssl->sock->peer_closed = false; + return ssl->sock->fd; + wexit: + ssl_close(t); + return ret; + #else + return -1; + #endif } - else { + + // Connect using lwip sockets + int flags; + struct timeval tv; + ssl->ssl_initialized = true; + mbedtls_ssl_init(&ssl->ctx); + mbedtls_ctr_drbg_init(&ssl->ctr_drbg); + mbedtls_ssl_config_init(&ssl->conf); + mbedtls_entropy_init(&ssl->entropy); + + if ((ret = mbedtls_ssl_config_defaults(&ssl->conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + if (transport_debug) LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret); + goto exit; } - ret = -1; - /* - if (ssl->client_cert_pem_data && ssl->client_key_pem_data) { - if (transport_debug) LOGW(TAG, "Client cert/key authentication not available"); + if ((ret = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg, mbedtls_entropy_func, &ssl->entropy, NULL, 0)) != 0) { + if (transport_debug) LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret); + goto exit; } - else if (ssl->client_cert_pem_data || ssl->client_key_pem_data) { + + mbedtls_x509_crt_init(&ssl->cacert); + if (ssl->cert_pem_data) { + ssl->verify_server = true; + if ((ret = mbedtls_x509_crt_parse(&ssl->cacert, ssl->cert_pem_data, ssl->cert_pem_len + 1)) < 0) { + if (transport_debug) LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\r\nDATA=%s,len=%d", -ret, (char*)ssl->cert_pem_data, ssl->cert_pem_len); + goto exit; + } + mbedtls_ssl_conf_ca_chain(&ssl->conf, &ssl->cacert, NULL); + mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + + if ((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) { + if (transport_debug) LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret); + goto exit; + } + } else { + mbedtls_ssl_conf_authmode(&ssl->conf, MBEDTLS_SSL_VERIFY_NONE); + } + + mbedtls_x509_crt_init(&ssl->client_cert); + mbedtls_pk_init(&ssl->client_key); + if (ssl->client_cert_pem_data && ssl->client_key_pem_data) { + ssl->mutual_authentication = true; + if ((ret = mbedtls_x509_crt_parse(&ssl->client_cert, ssl->client_cert_pem_data, ssl->client_cert_pem_len + 1)) < 0) { + if (transport_debug) LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\r\nDATA=%s,len=%d", -ret, (char*)ssl->client_cert_pem_data, ssl->client_cert_pem_len); + goto exit; + } + if ((ret = mbedtls_pk_parse_key(&ssl->client_key, ssl->client_key_pem_data, ssl->client_key_pem_len + 1, NULL, 0)) < 0) { + if (transport_debug) LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%x\r\nDATA=%s,len=%d", -ret, (char*)ssl->client_key_pem_data, ssl->client_key_pem_len); + goto exit; + } + + if ((ret = mbedtls_ssl_conf_own_cert(&ssl->conf, &ssl->client_cert, &ssl->client_key)) < 0) { + if (transport_debug) LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%x\n", -ret); + goto exit; + } + } else if (ssl->client_cert_pem_data || ssl->client_key_pem_data) { if (transport_debug) LOGE(TAG, "You have to provide both client_cert_pem and client_key_pem for mutual authentication"); goto exit; } - */ - ssl->sock->fd = at_get_socket(ssl->sock); - if (ssl->sock->fd < 0) { - vPortFree(ssl); - if (transport_debug) LOGE(TAG, "Error creating socket"); + mbedtls_ssl_conf_rng(&ssl->conf, mbedtls_ctr_drbg_random, &ssl->ctr_drbg); + + #ifdef MBEDTLS_DEBUG_C + mbedtls_ssl_conf_dbg(&ssl->conf, mbedtls_debug, NULL); + // Debug level (0-4) + mbedtls_debug_set_threshold(1); + #endif + + if ((ret = mbedtls_ssl_setup(&ssl->ctx, &ssl->conf)) != 0) { + if (transport_debug) LOGE(TAG, "mbedtls_ssl_setup returned -0x%x", -ret); goto exit; } - ssl->sock->link_id = ssl->sock->fd; - if (transport_debug) LOGI(TAG, "Socket created: %d", ssl->sock->fd); + if (transport_debug) LOGD(TAG, "mbedtls setup OK"); - #if MICROPY_PY_USE_WIFI - ret = wifi_connect(ssl->sock, host, port, 0); - #endif - if (ret < 0) { - if (transport_debug) LOGE(TAG, "error connecting %d", ret); + mbedtls_net_init(&ssl->client_fd); + + ms_to_timeval(timeout_ms, &tv); + + lwip_setsockopt(ssl->client_fd.fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + if (transport_debug) LOGD(TAG, "Connect to %s:%d", host, port); + char port_str[8] = {0}; + sprintf(port_str, "%d", port); + if ((ret = mbedtls_net_connect(&ssl->client_fd, host, port_str, MBEDTLS_NET_PROTO_TCP)) != 0) { + if (transport_debug) LOGE(TAG, "mbedtls_net_connect returned -%x", -ret); + goto exit; + } + + mbedtls_ssl_set_bio(&ssl->ctx, &ssl->client_fd, mbedtls_net_send, mbedtls_net_recv, NULL); + + if((ret = mbedtls_ssl_set_hostname(&ssl->ctx, host)) != 0) { + if (transport_debug) LOGE(TAG, " failed\n ! mbedtls_ssl_set_hostname returned %d\r\n", ret); goto exit; } - if (transport_debug) LOGD(TAG, "Connected to %s:%d", host, port); - ssl->sock->peer_closed = false; - return ssl->sock->fd; + + if (transport_debug) LOGM(TAG, "Performing the SSL/TLS handshake..."); + + while ((ret = mbedtls_ssl_handshake(&ssl->ctx)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + if (transport_debug) LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret); + goto exit; + } + } + + if (transport_debug) LOGD(TAG, "Verifying peer X.509 certificate..."); + + if ((flags = mbedtls_ssl_get_verify_result(&ssl->ctx)) != 0) { + /* In real life, we probably want to close connection if ret != 0 */ + LOGW(TAG, "Failed to verify peer certificate!"); + if (ssl->cert_pem_data) { + goto exit; + } + } else { + if (transport_debug) LOGD(TAG, "Certificate verified."); + } + + if (transport_debug) LOGD(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl->ctx)); + return 0; exit: ssl_close(t); return ret; @@ -103,23 +267,44 @@ static int ssl_poll_read(transport_handle_t t, int timeout_ms) { transport_ssl_t *ssl = transport_get_context_data(t); - int buflen = 0; - int wait_end = mp_hal_ticks_ms() + timeout_ms; - // wait for socket data - while (mp_hal_ticks_ms() <= wait_end) { - buflen = ssl->sock->buffer.length; - if (buflen > 0) break; - vTaskDelay(10); + if (net_active_interfaces & ACTIVE_INTERFACE_WIFI) { + #if MICROPY_PY_USE_WIFI + int buflen = 0; + int wait_end = mp_hal_ticks_ms() + timeout_ms; + // wait for socket data + while (mp_hal_ticks_ms() <= wait_end) { + buflen = ssl->sock->buffer.length; + if (buflen > 0) break; + vTaskDelay(10); + } + + return buflen; + #else + return 0; + #endif } - return buflen; + fd_set readset; + FD_ZERO(&readset); + FD_SET(ssl->client_fd.fd, &readset); + struct timeval timeout; + ms_to_timeval(timeout_ms, &timeout); + + return lwip_select(ssl->client_fd.fd + 1, &readset, NULL, NULL, &timeout); } //------------------------------------------------------------- static int ssl_poll_write(transport_handle_t t, int timeout_ms) { - //transport_ssl_t *ssl = transport_get_context_data(t); - return 1; + if (net_active_interfaces & ACTIVE_INTERFACE_WIFI) return 1; + + transport_ssl_t *ssl = transport_get_context_data(t); + fd_set writeset; + FD_ZERO(&writeset); + FD_SET(ssl->client_fd.fd, &writeset); + struct timeval timeout; + ms_to_timeval(timeout_ms, &timeout); + return lwip_select(ssl->client_fd.fd + 1, NULL, &writeset, NULL, &timeout); } //------------------------------------------------------------------------------------- @@ -128,9 +313,27 @@ static int ssl_write(transport_handle_t t, const char *buffer, int len, int time int ret = -1; transport_ssl_t *ssl = transport_get_context_data(t); - ret = wifi_send(ssl->sock, buffer, len); + if (net_active_interfaces & ACTIVE_INTERFACE_WIFI) { + #if MICROPY_PY_USE_WIFI + ret = wifi_send(ssl->sock, buffer, len); + if (ret <= 0) { + if (transport_debug) LOGE(TAG, "Write error, errno=%s", strerror(errno)); + } + return ret; + #else + return -1; + #endif + } + + int poll; + + if ((poll = transport_poll_write(t, timeout_ms)) <= 0) { + if (transport_debug) LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->client_fd.fd, timeout_ms); + return poll; + } + ret = mbedtls_ssl_write(&ssl->ctx, (const unsigned char *) buffer, len); if (ret <= 0) { - if (transport_debug) LOGE(TAG, "Write error, errno=%s", strerror(errno)); + if (transport_debug) LOGE(TAG, "mbedtls_ssl_write error, errno=%s", strerror(errno)); } return ret; } @@ -138,18 +341,29 @@ static int ssl_write(transport_handle_t t, const char *buffer, int len, int time //------------------------------------------------------------------------------ static int ssl_read(transport_handle_t t, char *buffer, int len, int timeout_ms) { - int poll = -1, ret; + int poll = -1, ret = -1; transport_ssl_t *ssl = transport_get_context_data(t); - if (ssl->sock->buffer.length <= 0) { + if (net_active_interfaces & ACTIVE_INTERFACE_WIFI) { + if (ssl->sock->buffer.length <= 0) { + if ((poll = transport_poll_read(t, timeout_ms)) <= 0) { + return poll; + } + } + #if MICROPY_PY_USE_WIFI + ret = wifi_read(ssl->sock, buffer, len); + #endif + if (ret <= 0) return -1; + return ret; + } + + if (mbedtls_ssl_get_bytes_avail(&ssl->ctx) <= 0) { if ((poll = transport_poll_read(t, timeout_ms)) <= 0) { return poll; } } - #if MICROPY_PY_USE_WIFI - ret = wifi_read(ssl->sock, buffer, len); - #endif - if (ret <= 0) { + ret = mbedtls_ssl_read(&ssl->ctx, (unsigned char *)buffer, len); + if (ret == 0) { return -1; } return ret; @@ -160,8 +374,35 @@ static int ssl_close(transport_handle_t t) { int ret = -1; transport_ssl_t *ssl = transport_get_context_data(t); - ret = wifi_close(ssl->sock); - ssl->sock->fd = -1; + + if (net_active_interfaces & ACTIVE_INTERFACE_WIFI) { + #if MICROPY_PY_USE_WIFI + ret = wifi_close(ssl->sock); + #endif + ssl->sock->fd = -1; + return ret; + } + + if (ssl->ssl_initialized) { + if (transport_debug) LOGD(TAG, "Cleanup mbedtls"); + mbedtls_ssl_close_notify(&ssl->ctx); + mbedtls_ssl_session_reset(&ssl->ctx); + mbedtls_net_free(&ssl->client_fd); + mbedtls_ssl_config_free(&ssl->conf); + if (ssl->verify_server) { + mbedtls_x509_crt_free(&ssl->cacert); + } + if (ssl->mutual_authentication) { + mbedtls_x509_crt_free(&ssl->client_cert); + mbedtls_pk_free(&ssl->client_key); + } + mbedtls_ctr_drbg_free(&ssl->ctr_drbg); + mbedtls_entropy_free(&ssl->entropy); + mbedtls_ssl_free(&ssl->ctx); + ssl->mutual_authentication = false; + ssl->ssl_initialized = false; + ssl->verify_server = false; + } return ret; } @@ -173,7 +414,7 @@ static int ssl_destroy(transport_handle_t t) vPortFree(ssl); return 0; } -#endif + //------------------------------------------------------------------------------- void transport_ssl_set_cert_data(transport_handle_t t, const char *data, int len) @@ -188,59 +429,56 @@ void transport_ssl_set_cert_data(transport_handle_t t, const char *data, int len //-------------------------------------------------------------------------------------- void transport_ssl_set_client_cert_data(transport_handle_t t, const char *data, int len) { - /* transport_ssl_t *ssl = transport_get_context_data(t); if (t && ssl) { ssl->client_cert_pem_data = (void *)data; ssl->client_cert_pem_len = len; } - */ } //------------------------------------------------------------------------------------- void transport_ssl_set_client_key_data(transport_handle_t t, const char *data, int len) { - /* transport_ssl_t *ssl = transport_get_context_data(t); if (t && ssl) { ssl->client_key_pem_data = (void *)data; ssl->client_key_pem_len = len; } - */ } //------------------------------------- transport_handle_t transport_ssl_init() { - #if MICROPY_PY_USE_WIFI - if (!(net_active_interfaces & ACTIVE_INTERFACE_WIFI)) { - if (transport_debug) LOGW(TAG, "Only available for WiFi network interface"); - return NULL; - } - int ssl_bufsize = 0; - bool f = wifi_set_ssl_buffer_size(&ssl_bufsize); - if (f) { - if (ssl_bufsize < 16384) { - ssl_bufsize = 16384; - wifi_set_ssl_buffer_size(&ssl_bufsize); - } - } transport_handle_t t = transport_init(); transport_ssl_t *ssl = pvPortMalloc(sizeof(transport_ssl_t)); K210_MEM_CHECK(TAG, ssl, return NULL); memset(ssl, 0, sizeof(transport_ssl_t)); - ssl->sock = _new_socket(); - ssl->sock->proto = WIFI_IPPROTO_SSL; - ssl->sock->fd = -1; + if (net_active_interfaces & ACTIVE_INTERFACE_WIFI) { + #if MICROPY_PY_USE_WIFI + int ssl_bufsize = 0; + bool f = wifi_set_ssl_buffer_size(&ssl_bufsize); + if (f) { + if (ssl_bufsize < 16384) { + ssl_bufsize = 16384; + wifi_set_ssl_buffer_size(&ssl_bufsize); + } + } + + ssl->sock = _new_socket(); + ssl->sock->proto = WIFI_IPPROTO_SSL; + ssl->sock->fd = -1; + #else + return NULL; + #endif + } + else { + mbedtls_net_init(&ssl->client_fd); + } transport_set_context_data(t, ssl); transport_set_func(t, ssl_connect, ssl_read, ssl_write, ssl_close, ssl_poll_read, ssl_poll_write, ssl_destroy); return t; - #else - if (transport_debug) LOGW(TAG, "Only available for WiFi network interface"); - return NULL; - #endif } #endif diff --git a/k210-freertos/mpy_support/standard_lib/network/modesp32.c b/k210-freertos/mpy_support/standard_lib/network/modesp32.c new file mode 100644 index 0000000..efb3523 --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/network/modesp32.c @@ -0,0 +1,684 @@ +/* + * This file is part of the MicroPython K210 project, https://github.com/loboris/MicroPython_K210_LoBo + * + * The MIT License (MIT) + * + * Copyright (c) 2020 LoBo (https://github.com/loboris) + * + * 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. + */ + +#include "mpconfigport.h" + +#if MICROPY_PY_USE_ESP32 + +#include +#include +#include +#include + +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "syslog.h" + +#include "py/runtime.h" +#include "py/objstr.h" + +#include "modmachine.h" +#include "mphalport.h" + +/* + * ESP32 communication format: + * --------------------------- + * status|command int16_t + * length uint16_t + * payload uint8_t[length] + * crc32 uint32_t + */ + +// ---------------------------------------------------- +// Those defines must be the same as in ESP32 firmware! +// ---------------------------------------------------- +#define USE_SPI_MASTER 1 +#define SPI_MASTER_POOLING 1 +#define DUMMY_BYTES 4 + +#define SPI_BUFFER_SIZE 4096 +#define SPI_FRAME_SIZE (SPI_BUFFER_SIZE+8) +#define REQUESTS_URL_MAX_SIZE 256 + +#define ESP_COMMAND_NONE 0 +#define ESP_COMMAND_ECHO 1 +#define ESP_COMMAND_GETTIME 2 +#define ESP_COMMAND_SETTIME 3 +#define ESP_COMMAND_GETVOLTAGE 4 +#define ESP_COMMAND_GETKEYS 5 +#define ESP_COMMAND_DEEPSLEEP 6 +#define ESP_COMMAND_LOGENABLE 7 +#define ESP_COMMAND_RQGET 100 +#define ESP_COMMAND_RQNEXT 101 + +#define ESP_COMMAND_WIFIINIT 200 +#define ESP_COMMAND_WIFISTATUS 201 +#define ESP_COMMAND_READ 255 + +#define ESP_ERROR_OK 0x0000 +#define ESP_ERROR_COMMAND_UNKNOWN 0x0100 +#define ESP_ERROR_CRC 0x0200 +#define ESP_ERROR_LENGTH 0x0300 +#define ESP_ERROR_NOCMD 0x0400 +#define ESP_ERROR_FRAME 0x0500 +#define ESP_ERROR_PROCESS 0x0600 +#define ESP_ERROR_TIMEOUT 0x0700 +#define ESP_ERROR_NOTCONNECTED 0x0800 +#define ESP_ERROR_SPISLAVE 0x0900 + +#define ESP_STATUS_RQFINISH 0x6000 +#define ESP_STATUS_MREQUEST 0x6100 +// ---------------------------------------------------- + + +static const char *esp32_errors[9] = { + "Ok", + "Cmd unknown", + "CRC Error", + "Wrong length", + "No command", + "Frame Error", + "Process error" + "Timeout", + "Not connected", + "SPI Slave error", +}; + + +typedef struct _esp32_obj_t { + mp_obj_base_t base; + machine_hw_spi_obj_t *spi_instance; + QueueHandle_t slave_queue; + int8_t rdy; + int rdy_pin; + bool double_wrspeed; + int16_t esp_cmdstat; + uint16_t esp_len; + uint32_t esp_writetime; + uint32_t esp_readtime; + uint32_t write_time; + uint32_t read_time; + uint32_t timeout; +} esp32_obj_t; + +#if !USE_SPI_MASTER +static uint8_t __attribute__((aligned(8))) esp_buffer[SPI_FRAME_SIZE]; +#endif + +const mp_obj_type_t esp32_type; +static const char TAG[] = "[ESP32]"; + + +//----------------------------------------------- +int urlencode(char *url, char *dest_url, int len) +{ + char c, code0, code1; + int idx = 0; + bool is_qstr = false; + + memset(dest_url, 0, len); + // Loop through url, if we find an encode char, replace with % and add hex as ASCII chars + // If we reach the query string (?), mark the query string encoding + while (*url) { + c = *url++; + if ((!is_qstr) && (c == '?')) is_qstr = true; + if (c == ' ') { + if (is_qstr) { + if (idx < len) dest_url[idx++]= '+'; + else idx++; + } + else { + if (idx < (len-3)) { + dest_url[idx++] = '%'; + dest_url[idx++] = '2'; + dest_url[idx++] = '0'; + } + else idx +=3; + } + } + else if (isalnum(c)) { + if (idx < len) dest_url[idx++] = c; + else idx++; + } + else { + code1 = (c & 0xf) + '0'; + if ((c & 0xf) > 9) code1 = (c & 0xf) - 10 + 'A'; + c = (c >> 4) & 0xf; + code0 = c +'0'; + if (c > 9) code0 = c - 10 + 'A'; + if (idx < (len-3)) { + dest_url[idx++] = '%'; + dest_url[idx++] = code0; + dest_url[idx++] = code1; + } + else idx +=3; + } + } + return idx; + +} + +#if !USE_SPI_MASTER +//------------------------------------------------------------ +static void esp32_spi_send(esp32_obj_t *self, uint8_t *buf_in) +{ + if (self->double_wrspeed) { + self->spi_instance->baudrate *= 2; + self->spi_instance->freq = (uint32_t)spi_dev_set_clock_rate(self->spi_instance->spi_device, self->spi_instance->baudrate); + } + if (self->esp_len > SPI_BUFFER_SIZE) { + self->esp_cmdstat |= ESP_ERROR_LENGTH; + return; + } + + // Wait for ready signal from ESP32 + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 0) { + } + uint64_t t_start = mp_hal_ticks_us(); + + // Prepare frame + memset(esp_buffer, 0, SPI_FRAME_SIZE); + if (buf_in) memcpy(esp_buffer + 4, buf_in, self->esp_len); + else self->esp_len = 0; + *(uint16_t *)(&esp_buffer[0]) = self->esp_cmdstat; + *(uint16_t *)(&esp_buffer[2]) = self->esp_len; + uint32_t crc = hal_crc32((const void *)esp_buffer, self->esp_len+4, 0); + memcpy(esp_buffer + self->esp_len + 4, (void *)&crc, 4); + + // and send it, the write length must be ALIGNED to 4 bytes! + int wrlen = self->esp_len+8; + if (wrlen & 3) wrlen = (wrlen & 0xFFFC) + 4; + int written = io_write(self->spi_instance->spi_device, esp_buffer, wrlen); + self->write_time = mp_hal_ticks_us() - t_start; + + // Wait until request processed by ESP32 + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 1) { + } + t_start = mp_hal_ticks_us(); + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 0) { + } + self->esp_writetime = mp_hal_ticks_us() - t_start; + + if (wrlen != written) { + self->esp_cmdstat |= ESP_ERROR_FRAME; + LOGW(TAG, "Write: sent %d, expected %d", written, wrlen); + } + if (self->double_wrspeed) { + self->spi_instance->baudrate /= 2; + self->spi_instance->freq = (uint32_t)spi_dev_set_clock_rate(self->spi_instance->spi_device, self->spi_instance->baudrate); + } + return; +} + +//------------------------------------------------- +static void esp32_spi_getStatLen(esp32_obj_t *self) +{ + // Wait for ready signal from ESP32 + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 0) { + } + + self->esp_cmdstat = 0; + int rdlen = io_read(self->spi_instance->spi_device, esp_buffer, 8); + + // Wait until request processed by ESP32 + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 1) { + } + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 0) { + } + + if (rdlen == 8) { + self->esp_cmdstat = *(uint16_t *)(&esp_buffer[0]); + self->esp_len = *(uint16_t *)(&esp_buffer[2]); + } + else { + self->esp_cmdstat = ESP_ERROR_LENGTH; + self->esp_len = 0; + } +} + +//------------------------------------------- +static void esp32_spi_read(esp32_obj_t *self) +{ + // Wait for ready signal from ESP32 + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 0) { + } + uint64_t t_start = mp_hal_ticks_us(); + + self->esp_cmdstat = 0; + // Align receive length to 4 bytes + int rdlen = self->esp_len+8; + if (rdlen & 3) rdlen = (rdlen & 0xFFFC) + 4; + rdlen = io_read(self->spi_instance->spi_device, esp_buffer, rdlen); + self->read_time = mp_hal_ticks_us() - t_start; + + // Wait until request processed by ESP32 + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 1) { + } + t_start = mp_hal_ticks_us(); + while (gpio_get_pin_value(gpiohs_handle, self->rdy_pin) == 0) { + } + self->esp_readtime = mp_hal_ticks_us() - t_start; + + if (rdlen >= 8) { + self->esp_cmdstat = *(uint16_t *)(&esp_buffer[0]); + uint16_t length = *(uint16_t *)(&esp_buffer[2]); + if (length <= SPI_BUFFER_SIZE) { + uint32_t crc = 0; + memcpy((void *)&crc, esp_buffer + length + 4, 4); + uint32_t calc_crc = hal_crc32((const void *)esp_buffer, length+4, 0); + if (crc == calc_crc) { + if (self->esp_len != length) { + LOGD(TAG, "Read: received length (%u) <> expected length (%u)", length, self->esp_len); + } + self->esp_len = length; + } + else { + LOGD(TAG, "Read: CRC Error, (len=%u)", length); + self->esp_cmdstat |= ESP_ERROR_CRC; + } + } + else { + LOGD(TAG, "Read: Length error (%u)", length); + self->esp_cmdstat |= ESP_ERROR_LENGTH; + } + } + else { + self->esp_cmdstat |= ESP_ERROR_FRAME; + } +} +#else + +// Request command processing from ESP32 +//--------------------------------------------------------------- +static void esp32_spi_command(esp32_obj_t *self, uint8_t *buf_in) +{ + if (self->esp_len > SPI_BUFFER_SIZE) { + self->esp_cmdstat |= ESP_ERROR_LENGTH; + return; + } + + spi_slave_command_t slv_cmd = {0}; + uint8_t *esp_buffer = self->spi_instance->slave_buffer+DUMMY_BYTES; + + // Clean previous slave messages + while (xQueueReceive(self->slave_queue, &slv_cmd, 0) == pdTRUE) { + ; + } + + // Prepare command frame in slave buffer + memset(esp_buffer, 0, SPI_FRAME_SIZE); + if (buf_in) memcpy(esp_buffer + 4, buf_in, self->esp_len); + else self->esp_len = 0; + *(uint16_t *)(&esp_buffer[0]) = self->esp_cmdstat; + *(uint16_t *)(&esp_buffer[2]) = self->esp_len; + uint32_t crc = hal_crc32((const void *)esp_buffer, self->esp_len+4, 0); + /*if (spi_slave_mutex) { + if (xSemaphoreTake(spi_slave_mutex, SPI_SLAVE_MUTEX_WAIT_TIME) != pdTRUE) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Slave buffer access timeout")); + } + }*/ + memcpy(esp_buffer + self->esp_len + 4, (void *)&crc, 4); + + int tmo = 1000; + if (self->spi_instance->handshake >= 0) { + while (tmo) { + // Pulse handshake line, request ESP32 to check the command + if (spi_slave_set_handshake(self->spi_instance->handle, 10)) break; + vTaskDelay(50); + tmo -= 50; + if (tmo == 0) { + self->esp_cmdstat |= ESP_ERROR_TIMEOUT; + self->esp_len = 0; + return; + } + } + } + + LOGD(TAG, "Command: Wait for ESP32 response..."); + uint64_t t_start = mp_hal_ticks_us(); + + // Wait until ESP has processed the command + tmo = 1000; + while (1) { + if (xQueueReceive(self->slave_queue, &slv_cmd, tmo / portTICK_RATE_MS) == pdTRUE) { + if (slv_cmd.err != SPI_CMD_ERR_OK) { + LOGD(TAG, "Command: Slave error %d", slv_cmd.err); + self->esp_cmdstat |= ESP_ERROR_SPISLAVE; + self->esp_len = 0; + break; + } + if (slv_cmd.cmd == SPI_CMD_WRITE_DATA_BLOCK) { + // ESP32 write, this should be the response to the command + self->read_time = mp_hal_ticks_us() - t_start; + + // The response frame is in the slave buffer + self->esp_cmdstat = *(uint16_t *)(&esp_buffer[0]); + uint16_t length = *(uint16_t *)(&esp_buffer[2]); + if (length <= SPI_BUFFER_SIZE) { + uint32_t crc = 0; + memcpy((void *)&crc, esp_buffer + length + 4, 4); + uint32_t calc_crc = hal_crc32((const void *)esp_buffer, length+4, 0); + if (crc == calc_crc) { + if (self->esp_len != length) { + LOGD(TAG, "Response: received length (%u) <> expected length (%u)", length, self->esp_len); + } + self->esp_len = length; + } + else { + LOGD(TAG, "Response: CRC Error, (len=%u)", length); + self->esp_cmdstat |= ESP_ERROR_CRC; + } + } + else { + LOGD(TAG, "Response: Length error (%u)", length); + self->esp_cmdstat |= ESP_ERROR_LENGTH; + } + break; + } + else { + // ESP32 read, first status(command&length) then full frame + if (slv_cmd.len == 4) continue; // status requested + // full command frame requested + self->write_time = mp_hal_ticks_us() - t_start; + t_start = mp_hal_ticks_us(); + tmo = self->timeout; + } + } + else { + self->esp_cmdstat |= ESP_ERROR_TIMEOUT; + self->esp_len = 0; + break; + } + } + memset(esp_buffer, 0, 4); + return; +} +#endif + +//------------------------------------- +static void checkSPI(esp32_obj_t *self) +{ + if (self->spi_instance->state != MACHINE_HW_SPI_STATE_INIT) { + mp_raise_msg(&mp_type_OSError, "SPI not initialized"); + } +} + +//---------------------------------------------------------------------------------------------------------------- +STATIC mp_obj_t modesp32_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) +{ + enum { ARG_spi, ARG_rdy, ARG_dwrspeed }; + const mp_arg_t allowed_args[] = { + { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + #if !USE_SPI_MASTER + { MP_QSTR_rdy, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_doublewrspeed, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = false } }, + #endif + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + esp32_obj_t *self = m_new_obj(esp32_obj_t); + mp_obj_t spi_inst = args[ARG_spi].u_obj; + if (!mp_obj_is_type(spi_inst, &machine_hw_spi_type)) { + mp_raise_ValueError("SPI instance expected"); + } + self->spi_instance = (machine_hw_spi_obj_t *)args[ARG_spi].u_obj; + #if USE_SPI_MASTER + if (self->spi_instance->spi_num != SPI_SLAVE) { + mp_raise_ValueError("SPI SLAVE instance expected"); + } + #else + if (self->spi_num > SPI_MASTER_1) { + mp_raise_ValueError("SPI MASTER instance expected"); + } + #endif + + self->base.type = &esp32_type; + + if (!machine_init_gpiohs()) { + mp_raise_ValueError("Cannot initialize gpiohs"); + } + + // === Get arguments === + + #if !USE_SPI_MASTER + self->double_wrspeed = args[ARG_dwrspeed].u_bool; + + // Configure RDY pin + self->rdy = args[ARG_rdy].u_int; + if (mp_used_pins[self->rdy].func != GPIO_FUNC_NONE) { + mp_raise_ValueError(gpiohs_funcs_in_use[mp_used_pins[self->rdy].func]); + } + self->rdy_pin = gpiohs_get_free(); + if (self->rdy_pin < 0) { + mp_raise_ValueError("Error configuring RDY pin"); + } + LOGD(TAG, "Configure RDY pin (%d)", self->rdy); + if (fpioa_set_function(self->rdy, FUNC_GPIOHS0 + self->rdy_pin) < 0) { + gpiohs_set_free(self->rdy_pin); + mp_raise_ValueError("Error configuring RDY pin"); + } + gpio_set_drive_mode(gpiohs_handle, self->rdy_pin, GPIO_DM_INPUT_PULL_UP); + mp_used_pins[self->rdy].func = GPIO_FUNC_PIN; + mp_used_pins[self->rdy].usedas = GPIO_USEDAS_HANDSHAKE; + mp_used_pins[self->rdy].gpio = self->rdy_pin; + mp_used_pins[self->rdy].fpioa_func = FUNC_GPIOHS0 + self->rdy_pin; + #else + + self->slave_queue = xQueueCreate(8, sizeof(spi_slave_command_t)); + if (self->spi_instance->slave_queue) { + self->spi_instance->slave_queue = NULL; + vQueueDelete(self->spi_instance->slave_queue); + } + self->spi_instance->slave_queue = self->slave_queue; + #endif + + return MP_OBJ_FROM_PTR(self); +} + +//-------------------------------------------------------------- +STATIC mp_obj_t modesp32_echo(mp_obj_t self_in, mp_obj_t wr_buf) +{ + esp32_obj_t *self = self_in; + checkSPI(self); + + self->esp_cmdstat = ESP_COMMAND_ECHO; + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + + uint8_t *srcbuf = (uint8_t *)src.buf; + self->esp_len = src.len; + + #if !USE_SPI_MASTER + esp32_spi_send(self, srcbuf); + + if ((self->esp_cmdstat >> 8) != ESP_ERROR_OK) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + + esp32_spi_read(self); + if ((self->esp_cmdstat >> 8) != ESP_ERROR_OK) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + LOGD(TAG, "Timings: write=(%u, %u), read=(%u, %u)", self->esp_writetime, self->write_time, self->esp_readtime, self->read_time); + #else + esp32_spi_command(self, srcbuf); + LOGD(TAG, "Timings: write=%u), read=%u", self->write_time, self->read_time); + uint8_t *esp_buffer = self->spi_instance->slave_buffer; + #endif + + if (memcmp(srcbuf, esp_buffer+4, self->esp_len) != 0) { + LOGD(TAG, "Error: echoed data does not match"); + return mp_const_false; + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(modesp32_echo_obj, modesp32_echo); + +//------------------------------------------------ +STATIC mp_obj_t modesp32_gettime(mp_obj_t self_in) +{ + esp32_obj_t *self = self_in; + checkSPI(self); + + self->esp_cmdstat = ESP_COMMAND_GETTIME; + self->esp_len = 0; + + #if !USE_SPI_MASTER + esp32_spi_send(self, NULL); + + if ((self->esp_cmdstat >> 8) != ESP_ERROR_OK) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + + self->esp_len = 4; + esp32_spi_read(self); + if ((self->esp_cmdstat >> 8) != ESP_ERROR_OK) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + LOGD(TAG, "Timings: write=(%u, %u), read=(%u, %u)", self->esp_writetime, self->write_time, self->esp_readtime, self->read_time); + #else + esp32_spi_command(self, NULL); + LOGD(TAG, "Timings: write=%u), read=%u", self->write_time, self->read_time); + uint8_t *esp_buffer = self->spi_instance->slave_buffer+4; + #endif + uint32_t seconds = 0; + memcpy(&seconds, esp_buffer+4, 4); + return mp_obj_new_int(seconds); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modesp32_gettime_obj, modesp32_gettime); + +//------------------------------------------------ +STATIC mp_obj_t modesp32_getvoltage(mp_obj_t self_in) +{ + esp32_obj_t *self = self_in; + checkSPI(self); + + self->esp_cmdstat = ESP_COMMAND_GETVOLTAGE; + self->esp_len = 0; + + #if !USE_SPI_MASTER + esp32_spi_send(self, NULL); + + if ((self->esp_cmdstat >> 8) != ESP_ERROR_OK) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + + self->esp_len = 8; + esp32_spi_read(self); + #else + esp32_spi_command(self, NULL); + LOGD(TAG, "Timings: write=%u), read=%u", self->write_time, self->read_time); + uint8_t *esp_buffer = self->spi_instance->slave_buffer+4; + #endif + if ((self->esp_cmdstat >> 8) != ESP_ERROR_OK) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + uint32_t v1, v2; + memcpy(&v1, esp_buffer+4, 4); + memcpy(&v2, esp_buffer+8, 4); + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_int(v1); + tuple[1] = mp_obj_new_int(v2); + + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modesp32_getvoltage_obj, modesp32_getvoltage); + +//--------------------------------------------------------------- +STATIC mp_obj_t modesp32_rqGET(mp_obj_t self_in, mp_obj_t wr_buf) +{ + esp32_obj_t *self = self_in; + checkSPI(self); + + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + + if (src.len >= REQUESTS_URL_MAX_SIZE) { + mp_raise_ValueError("Max url length exceeded"); + } + + self->esp_cmdstat = ESP_COMMAND_RQGET; + uint8_t *srcbuf = (uint8_t *)src.buf; + self->esp_len = src.len; + + #if !USE_SPI_MASTER + esp32_spi_send(self, srcbuf); + + if ((self->esp_cmdstat >> 8) != ESP_ERROR_OK) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + + // Get command status and response length + esp32_spi_getStatLen(self); + if (self->esp_cmdstat != ESP_COMMAND_RQGET) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + + esp32_spi_read(self); + if ((self->esp_cmdstat >> 8) != ESP_ERROR_OK) { + LOGD(TAG, "Error %d, %s", self->esp_cmdstat >> 8, esp32_errors[self->esp_cmdstat >> 8]); + return mp_const_false; + } + LOGD(TAG, "Timings: write=(%u, %u), read=(%u, %u)", self->esp_writetime, self->write_time, self->esp_readtime, self->read_time); + #else + esp32_spi_command(self, srcbuf); + LOGD(TAG, "Timings: write=%u), read=%u", self->write_time, self->read_time); + uint8_t *esp_buffer = self->spi_instance->slave_buffer+4; + #endif + return mp_obj_new_str((const char *)(esp_buffer+4), self->esp_len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(modesp32_rqGET_obj, modesp32_rqGET); + + +//============================================================= +STATIC const mp_rom_map_elem_t modesp32_locals_dict_table[] = { + // instance methods + { MP_ROM_QSTR(MP_QSTR_echo), MP_ROM_PTR(&modesp32_echo_obj) }, + { MP_ROM_QSTR(MP_QSTR_gettime), MP_ROM_PTR(&modesp32_gettime_obj) }, + { MP_ROM_QSTR(MP_QSTR_getvoltage), MP_ROM_PTR(&modesp32_getvoltage_obj) }, + { MP_ROM_QSTR(MP_QSTR_rqGET), MP_ROM_PTR(&modesp32_rqGET_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(modesp32_locals_dict, modesp32_locals_dict_table); + +//============================== +const mp_obj_type_t esp32_type = { + { &mp_type_type }, + .name = MP_QSTR_esp32, + .make_new = modesp32_make_new, + .locals_dict = (mp_obj_dict_t*)&modesp32_locals_dict, +}; + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/network/modmqtt.c b/k210-freertos/mpy_support/standard_lib/network/modmqtt.c index a86f7e5..6435d78 100644 --- a/k210-freertos/mpy_support/standard_lib/network/modmqtt.c +++ b/k210-freertos/mpy_support/standard_lib/network/modmqtt.c @@ -830,9 +830,11 @@ STATIC mp_obj_t mqtt_op_start(mp_obj_t self_in) mqtt_obj_t *self = MP_OBJ_TO_PTR(self_in); if ((self->client) && (self->client->state < MQTT_STATE_INIT)) { + /* if (self->client->connect_info.clean_session) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Client not in persistent session, free and create again")); } + */ int res = esp_mqtt_client_start(self->client); if (res != 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Error starting client")); diff --git a/k210-freertos/mpy_support/standard_lib/network/modnetwork.c b/k210-freertos/mpy_support/standard_lib/network/modnetwork.c index 34203e8..7ccc30a 100644 --- a/k210-freertos/mpy_support/standard_lib/network/modnetwork.c +++ b/k210-freertos/mpy_support/standard_lib/network/modnetwork.c @@ -52,6 +52,10 @@ extern const mp_obj_type_t wifi_type; extern const mp_obj_type_t gsm_type; #endif +#if MICROPY_PY_USE_ESP32 +extern const mp_obj_type_t esp32_type; +#endif + #if MICROPY_PY_USE_MQTT extern const mp_obj_type_t mqtt_type; #endif @@ -113,6 +117,10 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_gsm), MP_ROM_PTR(&gsm_type) }, #endif + #if MICROPY_PY_USE_ESP32 + { MP_ROM_QSTR(MP_QSTR_esp32), MP_ROM_PTR(&esp32_type) }, + #endif + #if MICROPY_PY_USE_MQTT { MP_ROM_QSTR(MP_QSTR_mqtt), MP_ROM_PTR(&mqtt_type) }, #endif diff --git a/k210-freertos/mpy_support/standard_lib/network/modrequests.c b/k210-freertos/mpy_support/standard_lib/network/modrequests.c index bd4a7a8..4ff44bd 100644 --- a/k210-freertos/mpy_support/standard_lib/network/modrequests.c +++ b/k210-freertos/mpy_support/standard_lib/network/modrequests.c @@ -41,9 +41,10 @@ #include "py/obj.h" #include "py/runtime.h" -#include "modmachine.h" #include "extmod/vfs.h" #include "py/stream.h" +#include "modmachine.h" +#include "modota.h" #define MAX_HTTP_RECV_BUFFER 512 #define FLOAT_FIELD_DEC_PLACES 8 @@ -57,14 +58,19 @@ static char *rqheader = NULL; static char *rqbody = NULL; static mp_obj_t rqbody_file = mp_const_none; static uint32_t flash_address = 0; -static uint32_t flash_length = 0; +static uint32_t expected_size = 0; +static uint32_t flash_end = 0; static int rqheader_ptr = 0; static int rqbody_len = DEFAULT_RQBODY_LEN; static int rqbody_ptr = 0; +static int rqbuffer_ptr = 0; static bool rqbody_ok = true; static bool rqheader_ok = true; static bool rq_base64 = false; static char *cert_pem = NULL; +static bool rqprogress = false; +static uint64_t rqtransfer_start = 0; +static int rq_rangestart, rq_rangeend; #if MICROPY_PY_USE_WIFI == 0 static bool wifi_task_semaphore_active; @@ -84,6 +90,10 @@ static bool wifi_task_semaphore_active; static int _http_event_handler(esp_http_client_event_t *evt) { mp_hal_wdt_reset(); + char tstr[32] = {'\0'}; + uint32_t saved = 0; + char *cdata = (char *)evt->data; + int len = evt->data_len; /* bool mutex_taken = false; if ((net_active_interfaces & ACTIVE_INTERFACE_WIFI)) { @@ -95,10 +105,16 @@ static int _http_event_handler(esp_http_client_event_t *evt) */ switch(evt->event_id) { case HTTP_EVENT_ERROR: - if (transport_debug) LOGW(TAG_EVENT, "ERROR"); + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] ERROR\r\n", mp_hal_ticks_ms() - rqtransfer_start); + } + else if (transport_debug) LOGW(TAG_EVENT, "ERROR"); break; case HTTP_EVENT_ON_CONNECTED: - if (transport_debug) LOGI(TAG_EVENT, "OnConnected"); + if (rqprogress) { + mp_printf(&mp_plat_print, "[%u ms] Connected\r\n", mp_hal_ticks_ms() - rqtransfer_start); + } + else if (transport_debug) LOGI(TAG_EVENT, "OnConnected"); break; case HTTP_EVENT_HEADER_SENT: if (transport_debug) { @@ -109,6 +125,16 @@ static int _http_event_handler(esp_http_client_event_t *evt) break; case HTTP_EVENT_ON_HEADER: if (transport_debug) LOGI(TAG_EVENT, "OnHeader: key=%s, value=%s", evt->header_key, evt->header_value); + if (strcmp(evt->header_key, "Content-Length") == 0) { + int64_t x = 0; + char *end; + errno = 0; + x = strtol(evt->header_value, &end, 10); + if ((errno == 0) && (*end == '\0') && (x < LONG_MAX) && (x > LONG_MIN)) { + expected_size = x; + if (transport_debug) LOGI(TAG_EVENT, "Content size: %ld", x); + } + } if ((rqheader != NULL) && (rqheader_ok)) { int len = rqheader_ptr + strlen(evt->header_key) + strlen(evt->header_value) + 5; if (len > DEFAULT_RQHEADER_LEN) rqheader_ok = false; @@ -123,61 +149,165 @@ static int _http_event_handler(esp_http_client_event_t *evt) } break; case HTTP_EVENT_ON_DATA: - if (transport_debug) LOGI(TAG_EVENT, "OnData: len=%d", evt->data_len); + // Data received + saved = 0; if (rqbody_ok) { if (rqbody_file != mp_const_none) { - int nwrite = mp_stream_posix_write((void *)rqbody_file, evt->data, evt->data_len); - if (nwrite <= 0) { - rqbody_ok = false; - if (transport_debug) LOGE(TAG_EVENT, "Download: Error writing to file %d", nwrite); - } - else { - if (transport_debug) LOGI(TAG_EVENT, "Write data to body file: rqptr=%d + %d", rqbody_ptr, nwrite); - rqbody_ptr += evt->data_len; + // Receive to file + // Copy received data to buffer + if (rqprogress) sprintf(tstr, "to file"); + while (len > 0) { + rqbody[rqbuffer_ptr++] = *cdata++; + len--; + if (rqbuffer_ptr >= rqbody_len) { + // buffer full, write to file + int nwrite = mp_stream_posix_write((void *)rqbody_file, rqbody, rqbuffer_ptr); + rqbody_ptr += rqbuffer_ptr; + if (nwrite != rqbuffer_ptr) { + rqbody_ok = false; + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] Error writing to file %d\r\n", mp_hal_ticks_ms() - rqtransfer_start, nwrite); + } + else if (transport_debug) LOGE(TAG_EVENT, "Error writing to file %d", nwrite); + break; + } + saved = rqbuffer_ptr; + rqbuffer_ptr = 0; + } } } else if (flash_address > 0) { - if ((rqbody_ptr+evt->data_len) <= flash_length) { - enum w25qxx_status_t res = w25qxx_write_data(flash_address+rqbody_ptr, evt->data, evt->data_len); - if (res != W25QXX_OK) { - rqbody_ok = false; - if (transport_debug) LOGE(TAG_EVENT, "Download: Error writing to Flash"); + // Receive to Flash + if (rqprogress) sprintf(tstr, "to Flash"); + if (flash_address < flash_end) { + // Copy received data to buffer (4K) + while (len > 0) { + rqbody[rqbuffer_ptr++] = *cdata++; + len--; + if (rqbuffer_ptr >= rqbody_len) { + // buffer full, write to flash + enum w25qxx_status_t res = w25qxx_write_data(flash_address+rqbody_ptr, (uint8_t *)rqbody, rqbuffer_ptr); + rqbody_ptr += rqbuffer_ptr; + if (res != W25QXX_OK) { + rqbody_ok = false; + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] Error writing to Flash\r\n", mp_hal_ticks_ms() - rqtransfer_start); + } + else if (transport_debug) LOGE(TAG_EVENT, "Error writing to Flash"); + break; + } + saved = rqbuffer_ptr; + rqbuffer_ptr = 0; + } } - else { - if (transport_debug) LOGI(TAG_EVENT, "Write data to Flash: rqptr=%d + %d", flash_address+rqbody_ptr, evt->data_len); - rqbody_ptr += evt->data_len; + } + else { + rqbody_ok = false; + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] Allowed Flash size exceeded\r\n", mp_hal_ticks_ms() - rqtransfer_start); } + else if (transport_debug) LOGE(TAG_EVENT, "Allowed Flash size exceeded"); } } else { - if (transport_debug) LOGI(TAG_EVENT, "Write data to body buffer: rqptr=%d/%d", rqbody_ptr, rqbody_len); + // Receive to body buffer + if (rqprogress) sprintf(tstr, "to buffer"); if (rqbody != NULL) { - int len = evt->data_len + rqbody_ptr; - if (len > rqbody_len) rqbody_ok = false; - if (rqbody_ok) { + len += rqbody_ptr; + if (len <= rqbody_len) { memcpy(rqbody + rqbody_ptr, evt->data, evt->data_len); rqbody_ptr += evt->data_len; rqbody[rqbody_ptr] = '\0'; - if (transport_debug) LOGD(TAG_EVENT, "Write %d byte(s) to body buffer", evt->data_len); + saved = evt->data_len; + } + else { + rqbody_ok = false; + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] Body buffer full\r\n", mp_hal_ticks_ms() - rqtransfer_start); + } + else if (transport_debug) LOGW(TAG_EVENT, "Body buffer full"); } - else if (transport_debug) LOGW(TAG_EVENT, "Body buffer size to small"); } else { rqbody_ok = false; - if (transport_debug) LOGW(TAG_EVENT, "No allocated body buffer"); + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] No allocated body buffer\r\n", mp_hal_ticks_ms() - rqtransfer_start); + } + else if (transport_debug) LOGW(TAG_EVENT, "No allocated body buffer"); } } } + if (rqprogress) { + if (saved) { + if (expected_size > 0) { + double recv = ((double)rqbody_ptr / (double)expected_size) * 100.0; + mp_printf(&mp_plat_print, "\r[%u ms] Download %s (%d): 0x%08X (%0.2f%%), %u", mp_hal_ticks_ms() - rqtransfer_start, tstr, rqbody_ok, rqbody_ptr, recv, saved); + } + else mp_printf(&mp_plat_print, "\r[%u ms] Download %s (%d): 0x%08X", mp_hal_ticks_ms() - rqtransfer_start, tstr, rqbody_ok, rqbody_ptr); + } + } + else if (transport_debug) LOGI(TAG_EVENT, "OnData (%d): len=%d", rqbody_ok, evt->data_len); break; case HTTP_EVENT_ON_FINISH: - if (transport_debug) LOGI(TAG_EVENT, "OnFinish"); + saved = 0; + if (((rqbody_file != mp_const_none) || (flash_address > 0)) && (rqbuffer_ptr > 0)) { + // Write remaining data in buffer to file or Flash + if (rqbody_file != mp_const_none) { + int nwrite = mp_stream_posix_write((void *)rqbody_file, rqbody, rqbuffer_ptr); + rqbody_ptr += rqbuffer_ptr; + if (nwrite != rqbuffer_ptr) { + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] Error writing to file %d\r\n", mp_hal_ticks_ms() - rqtransfer_start, nwrite); + } + else if (transport_debug) LOGE(TAG_EVENT, "Error writing to file %d", nwrite); + } + else saved = rqbuffer_ptr; + rqbody_ok = false; + rqbuffer_ptr = 0; + } + else { + uint32_t tmp_ptr = rqbody_ptr + rqbuffer_ptr; + while (rqbuffer_ptr < rqbody_len) { + rqbody[rqbuffer_ptr++] = 0xFF; + } + enum w25qxx_status_t res = w25qxx_write_data(flash_address+rqbody_ptr, (uint8_t *)rqbody, rqbuffer_ptr); + if (res != W25QXX_OK) { + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] Error writing to Flash\r\n", mp_hal_ticks_ms() - rqtransfer_start); + } + else if (transport_debug) LOGE(TAG_EVENT, "Error writing to Flash"); + } + else { + rqbody_ptr = tmp_ptr; + saved = rqbuffer_ptr; + } + rqbuffer_ptr = 0; + rqbody_ok = false; + } + } + if (rqprogress) { + if (saved) { + if (expected_size > 0) { + mp_printf(&mp_plat_print, "\r[%u ms] Download %s (1): 0x%08X (100.00%%), %u [Finished]\r\n", mp_hal_ticks_ms() - rqtransfer_start, tstr, rqbody_ptr, saved); + } + else mp_printf(&mp_plat_print, "\r[%u ms] Download %s (1): 0x%08X [Finished]\r\n", mp_hal_ticks_ms() - rqtransfer_start, tstr, rqbody_ptr); + } + else mp_printf(&mp_plat_print, "\r\nFinished\r\n"); + } + else if (transport_debug) LOGI(TAG_EVENT, "Finished"); break; case HTTP_EVENT_DISCONNECTED: - if (transport_debug) LOGI(TAG_EVENT, "Disconnected"); + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] Disconnected\r\n", mp_hal_ticks_ms() - rqtransfer_start); + } + else if (transport_debug) LOGI(TAG_EVENT, "Disconnected"); break; default: - if (transport_debug) LOGW(TAG_EVENT, "Unhandled: %d", evt->event_id); + if (rqprogress) { + mp_printf(&mp_plat_print, "\r\n[%u ms] Unhandled event (%d)\r\n", mp_hal_ticks_ms() - rqtransfer_start, evt->event_id); + } + else if (transport_debug) LOGW(TAG_EVENT, "Unhandled event (%d)", evt->event_id); } //if (mutex_taken) wifi_give_mutex(); return 0; @@ -469,7 +599,8 @@ static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char // GET to file mp_obj_t fargs[2]; fargs[0] = mp_obj_new_str(tofile, strlen(tofile)); - fargs[1] = mp_obj_new_str("wb", 2); + if (rq_rangestart > 0) fargs[1] = mp_obj_new_str("ab", 2); + else fargs[1] = mp_obj_new_str("wb", 2); rqbody_file = mp_vfs_open(2, fargs, (mp_map_t*)&mp_const_empty_map); if (!rqbody_file) { mp_raise_msg(&mp_type_OSError, "Error opening file"); @@ -484,6 +615,7 @@ static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char config.event_handler = _http_event_handler; config.buffer_size = buf_size; config.cert_pem = cert_pem; + config.timeout_ms = 5000; // Initialize the http_client and set the method esp_http_client_handle_t client = esp_http_client_init(&config); @@ -500,14 +632,21 @@ static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char rqbody = NULL; // Allocate buffers + // for headers rqheader = pvPortMalloc(DEFAULT_RQHEADER_LEN); if (rqheader != NULL) memset(rqheader, 0, DEFAULT_RQHEADER_LEN); else { if (rqbody_file != mp_const_none) mp_stream_close(rqbody_file); mp_raise_msg(&mp_type_OSError, "Error allocating header buffer"); } + + // and body int rqbody_size = rqbody_len; - if (tofile != NULL) rqbody_size = 384; + if ((tofile != NULL) || (flash_address > 0)) { + // For receive to file and Flash use 4K buffer + rqbody_size = 4096; + rqbody_len = 4096; + } rqbody = pvPortMalloc(rqbody_size); if (rqbody != NULL) memset(rqbody, 0, rqbody_size); else { @@ -516,10 +655,16 @@ static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char mp_raise_msg(&mp_type_OSError, "Error allocating body buffer"); } rqbody_ptr = 0; + rqbuffer_ptr = 0; rqbody_ok = true; rqheader_ok = true; wifi_task_semaphore_active = true; + if (flash_address > 0) { + // get buffer offset and align address to 4K + rqbuffer_ptr = flash_address & 0x0FFF; + flash_address &= 0xFFFFF000; + } // Execute requested method if (method == HTTP_METHOD_POST) { mp_obj_dict_t *dict; @@ -614,6 +759,12 @@ static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char if (!perform_handled) { // POST method is already handled, handle others methods here + if ((method == HTTP_METHOD_GET) && (rq_rangestart >= 0)) { + char temp_buf[128]; + sprintf(temp_buf, "bytes=%u-", rq_rangestart); + if (rq_rangeend > rq_rangestart) sprintf(temp_buf+strlen(temp_buf), "%u", rq_rangeend); + esp_http_client_set_header(client, "Range", temp_buf); + } MP_THREAD_GIL_EXIT(); err = esp_http_client_perform(client); esp_http_client_cleanup(client); @@ -635,21 +786,25 @@ static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char status = esp_http_client_get_status_code(client); - // Prepare the return value, 3-item tuple (status, header, body); - mp_obj_t tuple[3]; + // Prepare the return value, 6-item tuple (status, header, body, expected_size, received_size, flag); + mp_obj_t tuple[6]; tuple[0] = mp_obj_new_int(status); + tuple[3] = mp_obj_new_int(expected_size); + tuple[4] = mp_obj_new_int(rqbody_ptr); + tuple[5] = mp_obj_new_int(0); if ((rqheader) && (rqheader_ptr)) tuple[1] = mp_obj_new_str(rqheader, rqheader_ptr); else tuple[1] = mp_const_none; if (rqbody_file != mp_const_none) { - sprintf(rqbody, "Saved to file '%s', size=%d", tofile, rqbody_ptr); + sprintf(rqbody, "Saved to file '%s'", tofile); tuple[2] = mp_obj_new_str(rqbody, strlen(rqbody)); } else if (flash_address > 0) { - sprintf(rqbody, "Saved to Flash at '%08X', size=%d, expected=%u", flash_address, rqbody_ptr, flash_length); + sprintf(rqbody, "Saved to Flash at '%08X'", flash_address); tuple[2] = mp_obj_new_str(rqbody, strlen(rqbody)); + flash_end = flash_address + rqbody_ptr; } else if ((rqbody) && (rqbody_ptr)) tuple[2] = mp_obj_new_bytes((const byte*)rqbody, rqbody_ptr); else tuple[2] = mp_const_none; @@ -663,7 +818,7 @@ static mp_obj_t request(int method, bool multipart, mp_obj_t post_data_in, char rqbody = NULL; wifi_task_semaphore_active = false; - return mp_obj_new_tuple(3, tuple); + return mp_obj_new_tuple(6, tuple); } //----------------------------------------------------- @@ -713,12 +868,16 @@ void get_certificate(mp_obj_t cert, char *cert_pem_buf) STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { //network_checkConnection(); - enum { ARG_url, ARG_file, ARG_bufsize, ARG_flashsize }; + enum { ARG_url, ARG_dest, ARG_destidx, ARG_bufsize, ARG_size, ARG_rstart, ARG_rend, ARG_progress }; const mp_arg_t allowed_args[] = { - { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_file, MP_ARG_OBJ, { .u_obj = mp_const_none } }, - { MP_QSTR_bufsize, MP_ARG_INT, { .u_int = 1536 } }, - { MP_QSTR_flashsize, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_url, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_dest, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_dest_idx, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_bufsize, MP_ARG_INT, { .u_int = 1536 } }, + { MP_QSTR_size, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_rangestart, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_rangeend, MP_ARG_INT, { .u_int = -1 } }, + { MP_QSTR_progress, MP_ARG_BOOL, { .u_bool = false } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -727,32 +886,173 @@ STATIC mp_obj_t requests_GET(size_t n_args, const mp_obj_t *pos_args, mp_map_t * char *url = NULL; char *fname = NULL; flash_address = 0; - flash_length = 0; + uint32_t flash_start = 0; + expected_size = args[ARG_size].u_int; + flash_end = 0; + rqprogress = args[ARG_progress].u_bool; + rqtransfer_start = mp_hal_ticks_ms(); + rq_rangestart = args[ARG_rstart].u_int; + rq_rangeend = args[ARG_rend].u_int; + int bufsize = args[ARG_bufsize].u_int; + if ((bufsize < 512) || (bufsize > 8192)) bufsize = 1536; + int dest = args[ARG_destidx].u_int; + int flash_sector_offset = 0; + bool to_flash = false; url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); + char entry_name[BOOT_ENTRY_NAME_LEN] = {'\0'}; + sprintf(entry_name, "MicroPython"); #if MICROPY_PY_USE_OTA - if (mp_obj_is_int(args[ARG_file].u_obj)) { + uint32_t dest_address = 0; + uint32_t active_address, active_end_address, active_size; + ota_entry_t *active_entry = NULL; + + if (mp_obj_is_int(args[ARG_dest].u_obj)) { // GET to Flash, used for OTA download - flash_address = mp_obj_get_int(args[ARG_file].u_obj); - flash_length = mp_obj_get_int(args[ARG_flashsize].u_obj); - // Check address and size + flash_address = mp_obj_get_int(args[ARG_dest].u_obj); + if ((flash_address & 0x0FFF) != 0) { + mp_raise_ValueError("Flash address must be aligned to 4K"); + } + + flash_start = flash_address; + dest_address = flash_start; + if (rq_rangestart <= 4096) { + // download from the start + rq_rangestart = 0; + rq_rangeend = 0; + if ((dest < 0) || (dest > (BOOT_CONFIG_ITEMS-1))) { + mp_raise_ValueError("Wrong OTA destination index"); + } + // first download, reserve space for 5-byte header + flash_sector_offset = 5; + flash_address += 5; + } + else { + // resumed download + if ((rq_rangestart & 0x0FFF) != 0) { + mp_raise_ValueError("Flash resume address must be aligned to 4K"); + } + // adjust the flash address + flash_address += rq_rangestart; + // check previously (partially) saved firmware + if (!check_app_sha256(flash_start)) { + mp_raise_msg(&mp_type_OSError, "Previous download not verified"); + } + } + + // Get current firmware information + ota_entry_t default_entry = {0}; + default_entry.id_flags = (uint32_t)(MAGIC_ID + CFG_APP_FLAG_ACTIVE + CFG_APP_FLAG_SHA256); + default_entry.address = DEFAULT_APP_ADDRESS; + default_entry.size = get_fw_flash_size(DEFAULT_APP_ADDRESS); + sprintf(default_entry.name, "MicroPython"); + + int src = config_get_active(); + if (src < 0) nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Cannot get current boot entry")); + if (src == dest) mp_raise_ValueError("Source and destination equal!"); + + if (src >= 0) active_entry = (ota_entry_t *)(config_sector + (src*BOOT_CONFIG_ITEM_SIZE)); + else active_entry = &default_entry; + active_address = active_entry->address; + active_size = get_fw_flash_size(active_entry->address); + active_end_address = ((active_address + active_size) & 0xFFFFF000) + 0x1000; + + flash_end = dest_address + expected_size + 37; // firmware size + 5-byte header + 32-byte sha256 + if ((flash_end & 0x0FFF) > 0) { + flash_end &= 0xFFFFF000; + flash_end += 0x1000; + } + + // Check if valid destination Flash area is selected + if ( ((dest_address >= MICRO_PY_FLASHFS_START_ADDRESS) || (flash_end >= MICRO_PY_FLASHFS_START_ADDRESS)) || + ((dest_address < DEFAULT_APP_ADDRESS) || (flash_end < DEFAULT_APP_ADDRESS)) || + ((dest_address >= active_address) && (dest_address <= active_end_address)) || + ((flash_end >= active_address) && (flash_end <= active_end_address)) ) { + mp_raise_ValueError("Wrong Flash address and/or size!"); + } + to_flash = true; } - else if (mp_obj_is_str(args[ARG_file].u_obj)) { + else if (mp_obj_is_str(args[ARG_dest].u_obj)) { // GET to file - fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + fname = (char *)mp_obj_str_get_str(args[ARG_dest].u_obj); } #else - if (mp_obj_is_int(args[ARG_file].u_obj)) { + if (mp_obj_is_int(args[ARG_dest].u_obj)) { mp_raise_ValueError("Save to Flash not supported if OTA not enabled"); } - else if (mp_obj_is_str(args[ARG_file].u_obj)) { + else if (mp_obj_is_str(args[ARG_dest].u_obj)) { // GET to file - fname = (char *)mp_obj_str_get_str(args[ARG_file].u_obj); + fname = (char *)mp_obj_str_get_str(args[ARG_dest].u_obj); } #endif - mp_obj_t res = request(HTTP_METHOD_GET, false, NULL, url, fname, args[ARG_bufsize].u_int); + mp_obj_t res = request(HTTP_METHOD_GET, false, NULL, url, fname, bufsize); + + if (rqprogress) mp_printf(&mp_plat_print, "\r\nFinished in %u ms\r\n", mp_hal_ticks_ms() - rqtransfer_start); + + if ((to_flash) && (flash_end >= (flash_address + flash_sector_offset))) { + // OTA update, set application header and sha256 + // get returned tuple items + mp_obj_t *t_items; + size_t t_len; + mp_obj_tuple_get(res, &t_len, &t_items); + + // Check if download completed + bool complete = ((expected_size+flash_sector_offset) == rqbody_ptr); + if (!complete) { + // Download aborted, not all data received + if ((rqprogress) || (transport_debug)) LOGW(TAG, "Expected size different than received."); + t_items[5] = mp_obj_new_int(-1); + } + + bool curr_spi_check = w25qxx_spi_check; + w25qxx_spi_check = true; + + // Write the application size to Flash + if (uint32toflash(flash_start+1, flash_end-flash_start-flash_sector_offset)) { + // Calculate and write the application sha256 to Flash + if (calc_set_app_sha256(flash_start)) { + if (complete) { + // Set the destination entry data + if (backup_boot_sector()) { + ota_entry_t *dest_entry = (ota_entry_t *)(config_sector + (dest*BOOT_CONFIG_ITEM_SIZE)); + dest_entry->id_flags = (uint32_t)(MAGIC_ID + CFG_APP_FLAG_SHA256); + dest_entry->address = flash_start; + dest_entry->size = flash_end-flash_start-5; + dest_entry->crc32 = 0; + memcpy(dest_entry->name, entry_name, BOOT_ENTRY_NAME_LEN); + if ((rqprogress) || (transport_debug)) { + LOGI(TAG, "Adding boot entry #%d: %08X, %08X, %u", dest, dest_entry->id_flags, dest_entry->address, dest_entry->size); + } + + // Save modified boot sector + if (!write_boot_sector()) { + w25qxx_spi_check = curr_spi_check; + mp_raise_msg(&mp_type_OSError, "Error saving config sector."); + } + if ((rqprogress) || (transport_debug)) LOGI(TAG, "Boot entry #%d saved.", dest); + } + else { + w25qxx_spi_check = curr_spi_check; + mp_raise_msg(&mp_type_OSError, "Backup boot sector error"); + } + } + } + else { + w25qxx_spi_check = curr_spi_check; + mp_raise_msg(&mp_type_OSError, "Save sha256 error"); + } + } + else { + w25qxx_spi_check = curr_spi_check; + mp_raise_msg(&mp_type_OSError, "Save size error"); + } + w25qxx_spi_check = curr_spi_check; + } + else if (to_flash) { + mp_raise_msg(&mp_type_OSError, "Download to Flash failed"); + } return res; } @@ -775,7 +1075,10 @@ STATIC mp_obj_t requests_HEAD(size_t n_args, const mp_obj_t *pos_args, mp_map_t url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); flash_address = 0; - flash_length = 0; + expected_size = 0; + flash_end = 0; + rqprogress = false; + mp_obj_t res = request(HTTP_METHOD_HEAD, false, NULL, url, NULL, 1536); return res; @@ -811,7 +1114,10 @@ STATIC mp_obj_t requests_POST(size_t n_args, const mp_obj_t *pos_args, mp_map_t } flash_address = 0; - flash_length = 0; + expected_size = 0; + flash_end = 0; + rqprogress = false; + mp_obj_t res = request(HTTP_METHOD_POST, args[ARG_multipart].u_bool, args[ARG_params].u_obj, url, fname, args[ARG_bufsize].u_int); return res; @@ -836,7 +1142,10 @@ STATIC mp_obj_t requests_PUT(size_t n_args, const mp_obj_t *pos_args, mp_map_t * url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); flash_address = 0; - flash_length = 0; + expected_size = 0; + flash_end = 0; + rqprogress = false; + mp_obj_t res = request(HTTP_METHOD_PUT, false, args[ARG_data].u_obj, url, NULL, 1536); return res; @@ -861,7 +1170,10 @@ STATIC mp_obj_t requests_PATCH(size_t n_args, const mp_obj_t *pos_args, mp_map_t url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); flash_address = 0; - flash_length = 0; + expected_size = 0; + flash_end = 0; + rqprogress = false; + mp_obj_t res = request(HTTP_METHOD_PATCH, false, args[ARG_data].u_obj, url, NULL, 1536); return res; @@ -886,7 +1198,10 @@ STATIC mp_obj_t requests_DELETE(size_t n_args, const mp_obj_t *pos_args, mp_map_ url = (char *)mp_obj_str_get_str(args[ARG_url].u_obj); flash_address = 0; - flash_length = 0; + expected_size = 0; + flash_end = 0; + rqprogress = false; + mp_obj_t res = request(HTTP_METHOD_DELETE, false, args[ARG_data].u_obj, url, NULL, 1536); return res; diff --git a/k210-freertos/mpy_support/standard_lib/ulab/create.c b/k210-freertos/mpy_support/standard_lib/ulab/create.c new file mode 100644 index 0000000..c1c1eec --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/ulab/create.c @@ -0,0 +1,155 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2019-2020 Zoltán Vörös +*/ + + +#include "py/obj.h" +#include "py/runtime.h" +#include "create.h" + +mp_obj_t create_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t kind) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} } , + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t dtype = args[1].u_int; + if(!MP_OBJ_IS_INT(args[0].u_obj) && !MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) { + mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple")); + } + ndarray_obj_t *ndarray = NULL; + if(MP_OBJ_IS_INT(args[0].u_obj)) { + size_t n = mp_obj_get_int(args[0].u_obj); + ndarray = create_new_ndarray(1, n, dtype); + } else if(MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) { + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0].u_obj); + if(tuple->len != 2) { + mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple")); + } + ndarray = create_new_ndarray(mp_obj_get_int(tuple->items[0]), + mp_obj_get_int(tuple->items[1]), dtype); + } + if(kind == 1) { + mp_obj_t one = mp_obj_new_int(1); + for(size_t i=0; i < ndarray->array->len; i++) { + mp_binary_set_val_array(dtype, ndarray->array->items, i, one); + } + } + return MP_OBJ_FROM_PTR(ndarray); +} + +mp_obj_t create_zeros(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return create_zeros_ones(n_args, pos_args, kw_args, 0); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_zeros_obj, 0, create_zeros); + +mp_obj_t create_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return create_zeros_ones(n_args, pos_args, kw_args, 1); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_ones_obj, 0, create_ones); + +mp_obj_t create_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_M, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + size_t n = args[0].u_int, m; + int16_t k = args[2].u_int; + uint8_t dtype = args[3].u_int; + if(args[1].u_rom_obj == mp_const_none) { + m = n; + } else { + m = mp_obj_get_int(args[1].u_rom_obj); + } + + ndarray_obj_t *ndarray = create_new_ndarray(m, n, dtype); + mp_obj_t one = mp_obj_new_int(1); + size_t i = 0; + if((k >= 0) && (k < n)) { + while(k < n) { + mp_binary_set_val_array(dtype, ndarray->array->items, i*n+k, one); + k++; + i++; + } + } else if((k < 0) && (-k < m)) { + k = -k; + i = 0; + while(k < m) { + mp_binary_set_val_array(dtype, ndarray->array->items, k*n+i, one); + k++; + i++; + } + } + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_eye_obj, 0, create_eye); + +mp_obj_t create_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_num, MP_ARG_INT, {.u_int = 50} }, + { MP_QSTR_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_true} }, + { MP_QSTR_retstep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_false} }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint16_t len = args[2].u_int; + if(len < 2) { + mp_raise_ValueError(translate("number of points must be at least 2")); + } + mp_float_t value, step; + value = mp_obj_get_float(args[0].u_obj); + uint8_t typecode = args[5].u_int; + if(args[3].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj)-value)/(len-1); + else step = (mp_obj_get_float(args[1].u_obj)-value)/len; + ndarray_obj_t *ndarray = create_new_ndarray(1, len, typecode); + if(typecode == NDARRAY_UINT8) { + uint8_t *array = (uint8_t *)ndarray->array->items; + for(size_t i=0; i < len; i++, value += step) array[i] = (uint8_t)value; + } else if(typecode == NDARRAY_INT8) { + int8_t *array = (int8_t *)ndarray->array->items; + for(size_t i=0; i < len; i++, value += step) array[i] = (int8_t)value; + } else if(typecode == NDARRAY_UINT16) { + uint16_t *array = (uint16_t *)ndarray->array->items; + for(size_t i=0; i < len; i++, value += step) array[i] = (uint16_t)value; + } else if(typecode == NDARRAY_INT16) { + int16_t *array = (int16_t *)ndarray->array->items; + for(size_t i=0; i < len; i++, value += step) array[i] = (int16_t)value; + } else { + mp_float_t *array = (mp_float_t *)ndarray->array->items; + for(size_t i=0; i < len; i++, value += step) array[i] = value; + } + if(args[4].u_obj == mp_const_false) { + return MP_OBJ_FROM_PTR(ndarray); + } else { + mp_obj_t tuple[2]; + tuple[0] = ndarray; + tuple[1] = mp_obj_new_float(step); + return mp_obj_new_tuple(2, tuple); + } +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_linspace_obj, 2, create_linspace); diff --git a/k210-freertos/mpy_support/standard_lib/ulab/create.h b/k210-freertos/mpy_support/standard_lib/ulab/create.h new file mode 100644 index 0000000..e9304c9 --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/ulab/create.h @@ -0,0 +1,29 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2019-2020 Zoltán Vörös +*/ + +#ifndef _CREATE_ +#define _CREATE_ + +#include "ulab.h" +#include "ndarray.h" + +/* +mp_obj_t create_zeros(size_t , const mp_obj_t *, mp_map_t *); +mp_obj_t create_ones(size_t , const mp_obj_t *, mp_map_t *); +mp_obj_t create_eye(size_t , const mp_obj_t *, mp_map_t *); +mp_obj_t create_linspace(size_t , const mp_obj_t *, mp_map_t *); +*/ +MP_DECLARE_CONST_FUN_OBJ_KW(create_ones_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(create_zeros_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(create_eye_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(create_linspace_obj); + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/extras.c b/k210-freertos/mpy_support/standard_lib/ulab/extras.c new file mode 100644 index 0000000..08863b0 --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/ulab/extras.c @@ -0,0 +1,44 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Zoltán Vörös +*/ + +#include +#include +#include +#include "py/obj.h" +#include "py/runtime.h" +#include "py/misc.h" +#include "extras.h" + +#if ULAB_EXTRAS_MODULE + +mp_obj_t extras_spectrogram(size_t n_args, const mp_obj_t *args) { + if(n_args == 2) { + return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_SPECTRUM); + } else { + return fft_fft_ifft_spectrum(n_args, args[0], mp_const_none, FFT_SPECTRUM); + } +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(extras_spectrogram_obj, 1, 2, extras_spectrogram); + +STATIC const mp_rom_map_elem_t ulab_extras_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_extras) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_spectrogram), (mp_obj_t)&extras_spectrogram_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_extras_globals, ulab_extras_globals_table); + +mp_obj_module_t ulab_extras_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_extras_globals, +}; + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/extras.h b/k210-freertos/mpy_support/standard_lib/ulab/extras.h new file mode 100644 index 0000000..48ec8a0 --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/ulab/extras.h @@ -0,0 +1,24 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Zoltán Vörös +*/ + +#ifndef _EXTRA_ +#define _EXTRA_ + +#include "ulab.h" +#include "ndarray.h" +#include "fft.h" + +#if ULAB_EXTRAS_MODULE + +mp_obj_module_t ulab_extras_module; + +#endif +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/fft.c b/k210-freertos/mpy_support/standard_lib/ulab/fft.c index 91be9a1..2fa20b1 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/fft.c +++ b/k210-freertos/mpy_support/standard_lib/ulab/fft.c @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,25 +6,22 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #include #include #include #include #include "py/runtime.h" +#include "py/builtin.h" #include "py/binary.h" #include "py/obj.h" #include "py/objarray.h" #include "ndarray.h" #include "fft.h" -enum FFT_TYPE { - FFT_FFT, - FFT_IFFT, - FFT_SPECTRUM, -}; +#if ULAB_FFT_MODULE void fft_kernel(mp_float_t *real, mp_float_t *imag, int n, int isign) { // This is basically a modification of four1 from Numerical Recipes @@ -76,18 +74,18 @@ void fft_kernel(mp_float_t *real, mp_float_t *imag, int n, int isign) { mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) { if(!MP_OBJ_IS_TYPE(arg_re, &ulab_ndarray_type)) { - mp_raise_NotImplementedError("FFT is defined for ndarrays only"); + mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only")); } if(n_args == 2) { if(!MP_OBJ_IS_TYPE(arg_im, &ulab_ndarray_type)) { - mp_raise_NotImplementedError("FFT is defined for ndarrays only"); + mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only")); } } // Check if input is of length of power of 2 ndarray_obj_t *re = MP_OBJ_TO_PTR(arg_re); uint16_t len = re->array->len; if((len & (len-1)) != 0) { - mp_raise_ValueError("input array length must be power of 2"); + mp_raise_ValueError(translate("input array length must be power of 2")); } ndarray_obj_t *out_re = create_new_ndarray(1, len, NDARRAY_FLOAT); @@ -99,8 +97,9 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, memcpy((mp_float_t *)out_re->array->items, (mp_float_t *)re->array->items, re->bytes); } else { for(size_t i=0; i < len; i++) { - data_re[i] = ndarray_get_float_value(re->array->items, re->array->typecode, i); + *data_re++ = ndarray_get_float_value(re->array->items, re->array->typecode, i); } + data_re -= len; } ndarray_obj_t *out_im = create_new_ndarray(1, len, NDARRAY_FLOAT); mp_float_t *data_im = (mp_float_t *)out_im->array->items; @@ -108,29 +107,33 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, if(n_args == 2) { ndarray_obj_t *im = MP_OBJ_TO_PTR(arg_im); if (re->array->len != im->array->len) { - mp_raise_ValueError("real and imaginary parts must be of equal length"); + mp_raise_ValueError(translate("real and imaginary parts must be of equal length")); } if(im->array->typecode == NDARRAY_FLOAT) { memcpy((mp_float_t *)out_im->array->items, (mp_float_t *)im->array->items, im->bytes); } else { for(size_t i=0; i < len; i++) { - data_im[i] = ndarray_get_float_value(im->array->items, im->array->typecode, i); + *data_im++ = ndarray_get_float_value(im->array->items, im->array->typecode, i); } + data_im -= len; } } + if((type == FFT_FFT) || (type == FFT_SPECTRUM)) { fft_kernel(data_re, data_im, len, 1); if(type == FFT_SPECTRUM) { for(size_t i=0; i < len; i++) { - data_re[i] = MICROPY_FLOAT_C_FUN(sqrt)(data_re[i]*data_re[i] + data_im[i]*data_im[i]); + *data_re = MICROPY_FLOAT_C_FUN(sqrt)(*data_re * *data_re + *data_im * *data_im); + data_re++; + data_im++; } } } else { // inverse transform fft_kernel(data_re, data_im, len, -1); // TODO: numpy accepts the norm keyword argument for(size_t i=0; i < len; i++) { - data_re[i] /= len; - data_im[i] /= len; + *data_re++ /= len; + *data_im++ /= len; } } if(type == FFT_SPECTRUM) { @@ -151,6 +154,8 @@ mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) { } } +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft); + mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) { if(n_args == 2) { return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_IFFT); @@ -159,10 +164,19 @@ mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) { } } -mp_obj_t fft_spectrum(size_t n_args, const mp_obj_t *args) { - if(n_args == 2) { - return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_SPECTRUM); - } else { - return fft_fft_ifft_spectrum(n_args, args[0], mp_const_none, FFT_SPECTRUM); - } -} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft); + +STATIC const mp_rom_map_elem_t ulab_fft_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_fft) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_fft), (mp_obj_t)&fft_fft_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ifft), (mp_obj_t)&fft_ifft_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_fft_globals, ulab_fft_globals_table); + +mp_obj_module_t ulab_fft_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_fft_globals, +}; + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/fft.h b/k210-freertos/mpy_support/standard_lib/ulab/fft.h index 154e83f..08ceb05 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/fft.h +++ b/k210-freertos/mpy_support/standard_lib/ulab/fft.h @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,11 +6,12 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #ifndef _FFT_ #define _FFT_ +#include "ulab.h" #ifndef MP_PI #define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) @@ -17,7 +19,21 @@ #define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; } -mp_obj_t fft_fft(size_t , const mp_obj_t *); -mp_obj_t fft_ifft(size_t , const mp_obj_t *); -mp_obj_t fft_spectrum(size_t , const mp_obj_t *); +enum FFT_TYPE { + FFT_FFT, + FFT_IFFT, + FFT_SPECTRUM, +}; + +#if ULAB_FFT_MODULE + +extern mp_obj_module_t ulab_fft_module; + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj); + +mp_obj_t fft_fft_ifft_spectrum(size_t , mp_obj_t , mp_obj_t , uint8_t ); + +#endif #endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/filter.c b/k210-freertos/mpy_support/standard_lib/ulab/filter.c new file mode 100644 index 0000000..1c4d9fc --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/ulab/filter.c @@ -0,0 +1,99 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries +*/ + +#include +#include +#include +#include "py/obj.h" +#include "py/runtime.h" +#include "py/misc.h" +#include "filter.h" + +#if ULAB_FILTER_MODULE +mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_a, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_v, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type) || !MP_OBJ_IS_TYPE(args[1].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("convolve arguments must be ndarrays")); + } + + ndarray_obj_t *a = MP_OBJ_TO_PTR(args[0].u_obj); + ndarray_obj_t *c = MP_OBJ_TO_PTR(args[1].u_obj); + int len_a = a->array->len; + int len_c = c->array->len; + // deal with linear arrays only + if(a->m*a->n != len_a || c->m*c->n != len_c) { + mp_raise_TypeError(translate("convolve arguments must be linear arrays")); + } + if(len_a == 0 || len_c == 0) { + mp_raise_TypeError(translate("convolve arguments must not be empty")); + } + + int len = len_a + len_c - 1; // convolve mode "full" + ndarray_obj_t *out = create_new_ndarray(1, len, NDARRAY_FLOAT); + mp_float_t *outptr = out->array->items; + int off = len_c-1; + + if(a->array->typecode == NDARRAY_FLOAT && c->array->typecode == NDARRAY_FLOAT) { + mp_float_t* a_items = (mp_float_t*)a->array->items; + mp_float_t* c_items = (mp_float_t*)c->array->items; + for(int k=-off; karray->items, a->array->typecode, idx_a); + mp_float_t ci = ndarray_get_float_value(c->array->items, c->array->typecode, idx_c); + accum += ai * ci; + } + *outptr++ = accum; + } + } + + return out; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(filter_convolve_obj, 2, filter_convolve); + +STATIC const mp_rom_map_elem_t ulab_filter_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_filter) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_convolve), (mp_obj_t)&filter_convolve_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_filter_globals, ulab_filter_globals_table); + +mp_obj_module_t ulab_filter_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_filter_globals, +}; + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/filter.h b/k210-freertos/mpy_support/standard_lib/ulab/filter.h new file mode 100644 index 0000000..d4b6e7a --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/ulab/filter.h @@ -0,0 +1,25 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries +*/ + +#ifndef _FILTER_ +#define _FILTER_ + +#include "ulab.h" +#include "ndarray.h" + +#if ULAB_FILTER_MODULE + +extern mp_obj_module_t ulab_filter_module; + +MP_DECLARE_CONST_FUN_OBJ_KW(filter_convolve_obj); + +#endif +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/linalg.c b/k210-freertos/mpy_support/standard_lib/ulab/linalg.c index 9472912..15f403b 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/linalg.c +++ b/k210-freertos/mpy_support/standard_lib/ulab/linalg.c @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,9 +6,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #include #include #include @@ -16,76 +17,24 @@ #include "py/misc.h" #include "linalg.h" -mp_obj_t linalg_transpose(mp_obj_t self_in) { - ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); - // the size of a single item in the array - uint8_t _sizeof = mp_binary_get_size('@', self->array->typecode, NULL); - - // NOTE: - // if the matrices are square, we can simply swap items, but - // generic matrices can't be transposed in place, so we have to - // declare a temporary variable - - // NOTE: - // In the old matrix, the coordinate (m, n) is m*self->n + n - // We have to assign this to the coordinate (n, m) in the new - // matrix, i.e., to n*self->m + m (since the new matrix has self->m columns) - - // one-dimensional arrays can be transposed by simply swapping the dimensions - if((self->m != 1) && (self->n != 1)) { - uint8_t *c = (uint8_t *)self->array->items; - // self->bytes is the size of the bytearray, irrespective of the typecode - uint8_t *tmp = m_new(uint8_t, self->bytes); - for(size_t m=0; m < self->m; m++) { - for(size_t n=0; n < self->n; n++) { - memcpy(tmp+_sizeof*(n*self->m + m), c+_sizeof*(m*self->n + n), _sizeof); - } - } - memcpy(self->array->items, tmp, self->bytes); - m_del(uint8_t, tmp, self->bytes); - } - SWAP(size_t, self->m, self->n); - return mp_const_none; -} - -mp_obj_t linalg_reshape(mp_obj_t self_in, mp_obj_t shape) { - ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); - if(!MP_OBJ_IS_TYPE(shape, &mp_type_tuple) || (MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(shape)) != 2)) { - mp_raise_ValueError("shape must be a 2-tuple"); - } - - mp_obj_iter_buf_t iter_buf; - mp_obj_t item, iterable = mp_getiter(shape, &iter_buf); - uint16_t m, n; - item = mp_iternext(iterable); - m = mp_obj_get_int(item); - item = mp_iternext(iterable); - n = mp_obj_get_int(item); - if(m*n != self->m*self->n) { - // TODO: the proper error message would be "cannot reshape array of size %d into shape (%d, %d)" - mp_raise_ValueError("cannot reshape array (incompatible input/output shape)"); - } - self->m = m; - self->n = n; - return MP_OBJ_FROM_PTR(self); -} +#if ULAB_LINALG_MODULE mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, - { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { - mp_raise_TypeError("size is defined for ndarrays only"); + if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("size is defined for ndarrays only")); } else { ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); if(args[1].u_obj == mp_const_none) { return mp_obj_new_int(ndarray->array->len); - } else if(mp_obj_is_int(args[1].u_obj)) { + } else if(MP_OBJ_IS_INT(args[1].u_obj)) { uint8_t ax = mp_obj_get_int(args[1].u_obj); if(ax == 0) { if(ndarray->m == 1) { @@ -95,19 +44,21 @@ mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) } } else if(ax == 1) { if(ndarray->m == 1) { - mp_raise_ValueError("tuple index out of range"); + mp_raise_ValueError(translate("tuple index out of range")); } else { return mp_obj_new_int(ndarray->n); } } else { - mp_raise_ValueError("tuple index out of range"); + mp_raise_ValueError(translate("tuple index out of range")); } } else { - mp_raise_TypeError("wrong argument type"); + mp_raise_TypeError(translate("wrong argument type")); } } } +MP_DEFINE_CONST_FUN_OBJ_KW(linalg_size_obj, 1, linalg_size); + bool linalg_invert_matrix(mp_float_t *data, size_t N) { // returns true, of the inversion was successful, // false, if the matrix is singular @@ -153,14 +104,14 @@ bool linalg_invert_matrix(mp_float_t *data, size_t N) { mp_obj_t linalg_inv(mp_obj_t o_in) { // since inv is not a class method, we have to inspect the input argument first if(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) { - mp_raise_TypeError("only ndarrays can be inverted"); + mp_raise_TypeError(translate("only ndarrays can be inverted")); } ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in); if(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) { - mp_raise_TypeError("only ndarray objects can be inverted"); + mp_raise_TypeError(translate("only ndarray objects can be inverted")); } if(o->m != o->n) { - mp_raise_ValueError("only square matrices can be inverted"); + mp_raise_ValueError(translate("only square matrices can be inverted")); } ndarray_obj_t *inverted = create_new_ndarray(o->m, o->n, NDARRAY_FLOAT); mp_float_t *data = (mp_float_t *)inverted->array->items; @@ -178,17 +129,22 @@ mp_obj_t linalg_inv(mp_obj_t o_in) { // TODO: I am not sure this is needed here. Otherwise, // how should we free up the unused RAM of inverted? m_del(mp_float_t, inverted->array->items, o->n*o->n); - mp_raise_ValueError("input matrix is singular"); + mp_raise_ValueError(translate("input matrix is singular")); } return MP_OBJ_FROM_PTR(inverted); } +MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv); + mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) { // TODO: should the results be upcast? + if(!MP_OBJ_IS_TYPE(_m1, &ulab_ndarray_type) || !MP_OBJ_IS_TYPE(_m2, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("arguments must be ndarrays")); + } ndarray_obj_t *m1 = MP_OBJ_TO_PTR(_m1); ndarray_obj_t *m2 = MP_OBJ_TO_PTR(_m2); if(m1->n != m2->m) { - mp_raise_ValueError("matrix dimensions do not match"); + mp_raise_ValueError(translate("matrix dimensions do not match")); } // TODO: numpy uses upcasting here ndarray_obj_t *out = create_new_ndarray(m1->m, m2->n, NDARRAY_FLOAT); @@ -203,102 +159,21 @@ mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) { v2 = ndarray_get_float_value(m2->array->items, m2->array->typecode, k*m2->n+j); sum += v1 * v2; } - outdata[i*m1->m+j] = sum; + outdata[j*m1->m+i] = sum; } } return MP_OBJ_FROM_PTR(out); } -mp_obj_t linalg_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t kind) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} } , - { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - uint8_t dtype = args[1].u_int; - if(!mp_obj_is_int(args[0].u_obj) && !mp_obj_is_type(args[0].u_obj, &mp_type_tuple)) { - mp_raise_TypeError("input argument must be an integer or a 2-tuple"); - } - ndarray_obj_t *ndarray = NULL; - if(mp_obj_is_int(args[0].u_obj)) { - size_t n = mp_obj_get_int(args[0].u_obj); - ndarray = create_new_ndarray(1, n, dtype); - } else if(mp_obj_is_type(args[0].u_obj, &mp_type_tuple)) { - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0].u_obj); - if(tuple->len != 2) { - mp_raise_TypeError("input argument must be an integer or a 2-tuple"); - } - ndarray = create_new_ndarray(mp_obj_get_int(tuple->items[0]), - mp_obj_get_int(tuple->items[1]), dtype); - } - if(kind == 1) { - mp_obj_t one = mp_obj_new_int(1); - for(size_t i=0; i < ndarray->array->len; i++) { - mp_binary_set_val_array(dtype, ndarray->array->items, i, one); - } - } - return MP_OBJ_FROM_PTR(ndarray); -} - -mp_obj_t linalg_zeros(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - return linalg_zeros_ones(n_args, pos_args, kw_args, 0); -} - -mp_obj_t linalg_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - return linalg_zeros_ones(n_args, pos_args, kw_args, 1); -} - -mp_obj_t linalg_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_M, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, - { MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - size_t n = args[0].u_int, m; - int16_t k = args[2].u_int; - uint8_t dtype = args[3].u_int; - if(args[1].u_rom_obj == mp_const_none) { - m = n; - } else { - m = mp_obj_get_int(args[1].u_rom_obj); - } - - ndarray_obj_t *ndarray = create_new_ndarray(m, n, dtype); - mp_obj_t one = mp_obj_new_int(1); - size_t i = 0; - if((k >= 0) && (k < n)) { - while(k < n) { - mp_binary_set_val_array(dtype, ndarray->array->items, i*n+k, one); - k++; - i++; - } - } else if((k < 0) && (-k < m)) { - k = -k; - i = 0; - while(k < m) { - mp_binary_set_val_array(dtype, ndarray->array->items, k*n+i, one); - k++; - i++; - } - } - return MP_OBJ_FROM_PTR(ndarray); -} +MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot); mp_obj_t linalg_det(mp_obj_t oin) { - if(!mp_obj_is_type(oin, &ulab_ndarray_type)) { - mp_raise_TypeError("function defined for ndarrays only"); + if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("function defined for ndarrays only")); } ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); if(in->m != in->n) { - mp_raise_ValueError("input must be square matrix"); + mp_raise_ValueError(translate("input must be square matrix")); } mp_float_t *tmp = m_new(mp_float_t, in->n*in->n); @@ -329,13 +204,15 @@ mp_obj_t linalg_det(mp_obj_t oin) { return mp_obj_new_float(det); } +MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det); + mp_obj_t linalg_eig(mp_obj_t oin) { - if(!mp_obj_is_type(oin, &ulab_ndarray_type)) { - mp_raise_TypeError("function defined for ndarrays only"); + if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("function defined for ndarrays only")); } ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); if(in->m != in->n) { - mp_raise_ValueError("input must be square matrix"); + mp_raise_ValueError(translate("input must be square matrix")); } mp_float_t *array = m_new(mp_float_t, in->array->len); for(size_t i=0; i < in->array->len; i++) { @@ -347,7 +224,7 @@ mp_obj_t linalg_eig(mp_obj_t oin) { // compare entry (m, n) to (n, m) // TODO: this must probably be scaled! if(epsilon < MICROPY_FLOAT_C_FUN(fabs)(array[m*in->n + n] - array[n*in->n + m])) { - mp_raise_ValueError("input matrix is asymmetric"); + mp_raise_ValueError(translate("input matrix is asymmetric")); } } } @@ -440,7 +317,7 @@ mp_obj_t linalg_eig(mp_obj_t oin) { if(iterations == 0) { // the computation did not converge; numpy raises LinAlgError m_del(mp_float_t, array, in->array->len); - mp_raise_ValueError("iterations did not converge"); + mp_raise_ValueError(translate("iterations did not converge")); } ndarray_obj_t *eigenvalues = create_new_ndarray(1, in->n, NDARRAY_FLOAT); mp_float_t *eigvalues = (mp_float_t *)eigenvalues->array->items; @@ -455,3 +332,83 @@ mp_obj_t linalg_eig(mp_obj_t oin) { return tuple; return MP_OBJ_FROM_PTR(eigenvalues); } + +MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig); + +mp_obj_t linalg_cholesky(mp_obj_t oin) { + if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("function is defined for ndarrays only")); + } + + ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); + if(in->m != in->n) { + mp_raise_ValueError(translate("input must be square matrix")); + } + + ndarray_obj_t *L = create_new_ndarray(in->n, in->n, NDARRAY_FLOAT); + mp_float_t *array = (mp_float_t *)L->array->items; + + size_t pos = 0; + for(size_t m=0; m < in->m; m++) { // rows + for(size_t n=0; n < in->n; n++) { // columns + array[m*in->m+n] = ndarray_get_float_value(in->array->items, in->array->typecode, pos++); + } + } + + // make sure the matrix is symmetric + for(size_t m=0; m < in->m; m++) { // rows + for(size_t n=m+1; n < in->n; n++) { // columns + // compare entry (m, n) to (n, m) + if(epsilon < MICROPY_FLOAT_C_FUN(fabs)(array[m*in->n + n] - array[n*in->n + m])) { + mp_raise_ValueError(translate("input matrix is asymmetric")); + } + } + } + + // this is actually not needed, but Cholesky in numpy returns the lower triangular matrix + for(size_t i=0; i < in->m; i++) { // rows + for(size_t j=i+1; j < in->n; j++) { // columns + array[i*in->m + j] = 0.0; + } + } + mp_float_t sum = 0.0; + for(size_t i=0; i < in->m; i++) { // rows + for(size_t j=0; j <= i; j++) { // columns + sum = array[i*in->m + j]; + for(size_t k=0; k < j; k++) { + sum -= array[i*in->n + k] * array[j*in->n + k]; + } + if(i == j) { + if(sum <= 0.0) { + mp_raise_ValueError(translate("matrix is not positive definite")); + } else { + array[i*in->m+i] = MICROPY_FLOAT_C_FUN(sqrt)(sum); + } + } else { + array[i*in->m + j] = sum / array[j*in->m+j]; + } + } + } + return MP_OBJ_FROM_PTR(L); +} + +MP_DEFINE_CONST_FUN_OBJ_1(linalg_cholesky_obj, linalg_cholesky); + +STATIC const mp_rom_map_elem_t ulab_linalg_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_linalg) }, + { MP_ROM_QSTR(MP_QSTR_size), (mp_obj_t)&linalg_size_obj }, + { MP_ROM_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj }, + { MP_ROM_QSTR(MP_QSTR_dot), (mp_obj_t)&linalg_dot_obj }, + { MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj }, + { MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj }, + { MP_ROM_QSTR(MP_QSTR_cholesky), (mp_obj_t)&linalg_cholesky_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_linalg_globals, ulab_linalg_globals_table); + +mp_obj_module_t ulab_linalg_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_linalg_globals, +}; + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/linalg.h b/k210-freertos/mpy_support/standard_lib/ulab/linalg.h index 111dad1..f104571 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/linalg.h +++ b/k210-freertos/mpy_support/standard_lib/ulab/linalg.h @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,16 +6,15 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #ifndef _LINALG_ #define _LINALG_ +#include "ulab.h" #include "ndarray.h" -#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; } - #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define epsilon 1.2e-7 #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE @@ -23,17 +23,19 @@ #define JACOBI_MAX 20 -mp_obj_t linalg_transpose(mp_obj_t ); -mp_obj_t linalg_reshape(mp_obj_t , mp_obj_t ); -mp_obj_t linalg_size(size_t , const mp_obj_t *, mp_map_t *); +#if ULAB_LINALG_MODULE || ULAB_POLY_MODULE bool linalg_invert_matrix(mp_float_t *, size_t ); -mp_obj_t linalg_inv(mp_obj_t ); -mp_obj_t linalg_dot(mp_obj_t , mp_obj_t ); -mp_obj_t linalg_zeros(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t linalg_ones(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t linalg_eye(size_t , const mp_obj_t *, mp_map_t *); +#endif -mp_obj_t linalg_det(mp_obj_t ); -mp_obj_t linalg_eig(mp_obj_t ); +#if ULAB_LINALG_MODULE +extern mp_obj_module_t ulab_linalg_module; + +MP_DECLARE_CONST_FUN_OBJ_KW(linalg_size_obj); +MP_DECLARE_CONST_FUN_OBJ_1(linalg_inv_obj); +MP_DECLARE_CONST_FUN_OBJ_2(linalg_dot_obj); +MP_DECLARE_CONST_FUN_OBJ_1(linalg_det_obj); +MP_DECLARE_CONST_FUN_OBJ_1(linalg_eig_obj); + +#endif #endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/micropython.mk b/k210-freertos/mpy_support/standard_lib/ulab/micropython.mk index b9e9c42..bce4dae 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/micropython.mk +++ b/k210-freertos/mpy_support/standard_lib/ulab/micropython.mk @@ -3,11 +3,14 @@ USERMODULES_DIR := $(USERMOD_DIR) # Add all C files to SRC_USERMOD. SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c +SRC_USERMOD += $(USERMODULES_DIR)/create.c SRC_USERMOD += $(USERMODULES_DIR)/linalg.c SRC_USERMOD += $(USERMODULES_DIR)/vectorise.c SRC_USERMOD += $(USERMODULES_DIR)/poly.c SRC_USERMOD += $(USERMODULES_DIR)/fft.c SRC_USERMOD += $(USERMODULES_DIR)/numerical.c +SRC_USERMOD += $(USERMODULES_DIR)/filter.c +SRC_USERMOD += $(USERMODULES_DIR)/extras.c SRC_USERMOD += $(USERMODULES_DIR)/ulab.c # We can add our module folder to include paths if needed diff --git a/k210-freertos/mpy_support/standard_lib/ulab/ndarray.c b/k210-freertos/mpy_support/standard_lib/ulab/ndarray.c index 2cdd38f..5fc6479 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/ndarray.c +++ b/k210-freertos/mpy_support/standard_lib/ulab/ndarray.c @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,9 +6,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #include #include #include @@ -153,7 +154,7 @@ mp_obj_t ndarray_copy(mp_obj_t self_in) { STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT } }, }; @@ -164,16 +165,13 @@ STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_m return dtype; } -mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 1, 2, true); - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - uint8_t dtype = ndarray_init_helper(n_args, args, &kw_args); +STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args, mp_map_t *kw_args) { + uint8_t dtype = ndarray_init_helper(n_args, args, kw_args); size_t len1, len2=0, i=0; mp_obj_t len_in = mp_obj_len_maybe(args[0]); if (len_in == MP_OBJ_NULL) { - mp_raise_ValueError("first argument must be an iterable"); + mp_raise_ValueError(translate("first argument must be an iterable")); } else { // len1 is either the number of rows (for matrices), or the number of elements (row vectors) len1 = MP_OBJ_SMALL_INT_VALUE(len_in); @@ -189,7 +187,7 @@ mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, // Next, we have to check, whether all elements in the outer loop have the same length if(i > 0) { if(len2 != MP_OBJ_SMALL_INT_VALUE(len_in)) { - mp_raise_ValueError("iterables are not of the same length"); + mp_raise_ValueError(translate("iterables are not of the same length")); } } len2 = MP_OBJ_SMALL_INT_VALUE(len_in); @@ -214,14 +212,31 @@ mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, return MP_OBJ_FROM_PTR(self); } -size_t slice_length(mp_bound_slice_t slice) { - // TODO: check, whether this is true! - if(slice.step < 0) { - slice.step = -slice.step; - return (slice.start - slice.stop) / slice.step; - } else { - return (slice.stop - slice.start) / slice.step; +#ifdef CIRCUITPY +mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 1, 2, true); + size_t n_kw = 0; + if (kw_args != 0) { + n_kw = kw_args->used; } + mp_map_init_fixed_table(kw_args, n_kw, args + n_args); + return ndarray_make_new_core(type, n_args, n_kw, args, kw_args); +} +#else +mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 2, true); + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + return ndarray_make_new_core(type, n_args, n_kw, args, &kw_args); +} +#endif + +size_t slice_length(mp_bound_slice_t slice) { + int32_t len, correction = 1; + if(slice.step > 0) correction = -1; + len = (slice.stop - slice.start + (slice.step + correction)) / slice.step; + if(len < 0) return 0; + return (size_t)len; } size_t true_length(mp_obj_t bool_list) { @@ -231,7 +246,7 @@ size_t true_length(mp_obj_t bool_list) { mp_obj_t item, iterable = mp_getiter(bool_list, &iter_buf); size_t trues = 0; while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if(!mp_obj_is_type(item, &mp_type_bool)) { + if(!MP_OBJ_IS_TYPE(item, &mp_type_bool)) { // numpy seems to be a little bit inconsistent in when an index is considered // to be True/False. Bail out immediately, if the items are not True/False return 0; @@ -247,20 +262,20 @@ mp_bound_slice_t generate_slice(mp_uint_t n, mp_obj_t index) { // micropython seems to have difficulties with negative steps mp_bound_slice_t slice; if(MP_OBJ_IS_TYPE(index, &mp_type_slice)) { - mp_seq_get_fast_slice_indexes(n, index, &slice); - } else if(mp_obj_is_int(index)) { + mp_obj_slice_indices(index, n, &slice); + } else if(MP_OBJ_IS_INT(index)) { int32_t _index = mp_obj_get_int(index); if(_index < 0) { _index += n; } if((_index >= n) || (_index < 0)) { - mp_raise_msg(&mp_type_IndexError, "index is out of bounds"); + mp_raise_msg(&mp_type_IndexError, translate("index is out of bounds")); } slice.start = _index; slice.stop = _index + 1; slice.step = 1; } else { - mp_raise_msg(&mp_type_IndexError, "indices must be integers, slices, or Boolean lists"); + mp_raise_msg(&mp_type_IndexError, translate("indices must be integers, slices, or Boolean lists")); } return slice; } @@ -289,8 +304,8 @@ mp_obj_t insert_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n, mp_obj_t row_list, mp_obj_t column_list, ndarray_obj_t *values) { if((m != values->m) && (n != values->n)) { - if((values->array->len != 1)) { // not a single item - mp_raise_ValueError("could not broadast input array from shape"); + if(values->array->len != 1) { // not a single item + mp_raise_ValueError(translate("could not broadast input array from shape")); } } size_t cindex, rindex; @@ -376,10 +391,6 @@ mp_obj_t iterate_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n, mp_bound_slice_t row, mp_bound_slice_t column, mp_obj_t row_list, mp_obj_t column_list, ndarray_obj_t *values) { - if((m == 0) || (n == 0)) { - mp_raise_msg(&mp_type_IndexError, "empty index range"); - } - if(values != NULL) { return insert_slice_list(ndarray, m, n, row, column, row_list, column_list, values); } @@ -462,7 +473,7 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t mp_bound_slice_t row_slice = simple_slice(0, 0, 1), column_slice = simple_slice(0, 0, 1); size_t m = 0, n = 0; - if(mp_obj_is_int(index) && (ndarray->m == 1) && (values == NULL)) { + if(MP_OBJ_IS_INT(index) && (ndarray->m == 1) && (values == NULL)) { // we have a row vector, and don't want to assign column_slice = generate_slice(ndarray->n, index); if(slice_length(column_slice) == 1) { // we were asked for a single item @@ -471,7 +482,7 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t } } - if(mp_obj_is_int(index) || MP_OBJ_IS_TYPE(index, &mp_type_slice)) { + if(MP_OBJ_IS_INT(index) || MP_OBJ_IS_TYPE(index, &mp_type_slice)) { if(ndarray->m == 1) { // we have a row vector column_slice = generate_slice(ndarray->n, index); row_slice = simple_slice(0, 1, 1); @@ -495,15 +506,15 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t else { // we certainly have a tuple, so let us deal with it mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(index); if(tuple->len != 2) { - mp_raise_msg(&mp_type_IndexError, "too many indices"); + mp_raise_msg(&mp_type_IndexError, translate("too many indices")); } if(!(MP_OBJ_IS_TYPE(tuple->items[0], &mp_type_list) || MP_OBJ_IS_TYPE(tuple->items[0], &mp_type_slice) || - mp_obj_is_int(tuple->items[0])) || + MP_OBJ_IS_INT(tuple->items[0])) || !(MP_OBJ_IS_TYPE(tuple->items[1], &mp_type_list) || MP_OBJ_IS_TYPE(tuple->items[1], &mp_type_slice) || - mp_obj_is_int(tuple->items[1]))) { - mp_raise_msg(&mp_type_IndexError, "indices must be integers, slices, or Boolean lists"); + MP_OBJ_IS_INT(tuple->items[1]))) { + mp_raise_msg(&mp_type_IndexError, translate("indices must be integers, slices, or Boolean lists")); } if(MP_OBJ_IS_TYPE(tuple->items[0], &mp_type_list)) { // rows are indexed by Boolean list m = true_length(tuple->items[0]); @@ -543,11 +554,11 @@ mp_obj_t ndarray_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return ndarray_get_slice(self, index, NULL); } else { // assignment to slices; the value must be an ndarray, or a scalar if(!MP_OBJ_IS_TYPE(value, &ulab_ndarray_type) && - !mp_obj_is_int(value) && !mp_obj_is_float(value)) { - mp_raise_ValueError("right hand side must be an ndarray, or a scalar"); + !MP_OBJ_IS_INT(value) && !mp_obj_is_float(value)) { + mp_raise_ValueError(translate("right hand side must be an ndarray, or a scalar")); } else { ndarray_obj_t *values = NULL; - if(mp_obj_is_int(value)) { + if(MP_OBJ_IS_INT(value)) { values = create_new_ndarray(1, 1, self->array->typecode); mp_binary_set_val_array(values->array->typecode, values->array->items, 0, value); } else if(mp_obj_is_float(value)) { @@ -625,22 +636,14 @@ mp_obj_t ndarray_shape(mp_obj_t self_in) { return mp_obj_new_tuple(2, tuple); } -mp_obj_t ndarray_rawsize(mp_obj_t self_in) { - // returns a 5-tuple with the - // - // 0. number of rows - // 1. number of columns - // 2. length of the storage (should be equal to the product of 1. and 2.) - // 3. length of the data storage in bytes - // 4. datum size in bytes +mp_obj_t ndarray_size(mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(self->array->len); +} + +mp_obj_t ndarray_itemsize(mp_obj_t self_in) { ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(self->m); - tuple->items[1] = MP_OBJ_NEW_SMALL_INT(self->n); - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(self->array->len); - tuple->items[3] = MP_OBJ_NEW_SMALL_INT(self->bytes); - tuple->items[4] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->array->typecode, NULL)); - return tuple; + return MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->array->typecode, NULL)); } mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -655,7 +658,7 @@ mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a GET_STR_DATA_LEN(args[0].u_obj, order, len); if((len != 1) || ((memcmp(order, "C", 1) != 0) && (memcmp(order, "F", 1) != 0))) { - mp_raise_ValueError("flattening order must be either 'C', or 'F'"); + mp_raise_ValueError(translate("flattening order must be either 'C', or 'F'")); } // if order == 'C', we simply have to set m, and n, there is nothing else to do @@ -678,11 +681,6 @@ mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a return self_copy; } -mp_obj_t ndarray_asbytearray(mp_obj_t self_in) { - ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->array); -} - // Binary operations mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { @@ -694,7 +692,7 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { // TODO: implement in-place operators mp_obj_t RHS = MP_OBJ_NULL; bool rhs_is_scalar = true; - if(mp_obj_is_int(rhs)) { + if(MP_OBJ_IS_INT(rhs)) { int32_t ivalue = mp_obj_get_int(rhs); if((ivalue > 0) && (ivalue < 256)) { CREATE_SINGLE_ITEM(RHS, uint8_t, NDARRAY_UINT8, ivalue); @@ -715,12 +713,12 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { rhs_is_scalar = false; } //else - if(mp_obj_is_type(lhs, &ulab_ndarray_type) && mp_obj_is_type(RHS, &ulab_ndarray_type)) { + if(MP_OBJ_IS_TYPE(lhs, &ulab_ndarray_type) && MP_OBJ_IS_TYPE(RHS, &ulab_ndarray_type)) { // next, the ndarray stuff ndarray_obj_t *ol = MP_OBJ_TO_PTR(lhs); ndarray_obj_t *or = MP_OBJ_TO_PTR(RHS); if(!rhs_is_scalar && ((ol->m != or->m) || (ol->n != or->n))) { - mp_raise_ValueError("operands could not be broadcast together"); + mp_raise_ValueError(translate("operands could not be broadcast together")); } // At this point, the operands should have the same shape switch(op) { @@ -823,7 +821,7 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, mp_float_t, ol, or, op); } } else { // this should never happen - mp_raise_TypeError("wrong input type"); + mp_raise_TypeError(translate("wrong input type")); } // this instruction should never be reached, but we have to make the compiler happy return MP_OBJ_NULL; @@ -831,7 +829,7 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { return MP_OBJ_NULL; // op not supported } } else { - mp_raise_TypeError("wrong operand type on the right hand side"); + mp_raise_TypeError(translate("wrong operand type on the right hand side")); } } @@ -849,7 +847,7 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_INVERT: if(self->array->typecode == NDARRAY_FLOAT) { - mp_raise_ValueError("operation is not supported for given type"); + mp_raise_ValueError(translate("operation is not supported for given type")); } // we can invert the content byte by byte, there is no need to distinguish // between different typecodes @@ -909,3 +907,67 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) { default: return MP_OBJ_NULL; // operator not supported } } + +mp_obj_t ndarray_transpose(mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + // the size of a single item in the array + uint8_t _sizeof = mp_binary_get_size('@', self->array->typecode, NULL); + + // NOTE: + // if the matrices are square, we can simply swap items, but + // generic matrices can't be transposed in place, so we have to + // declare a temporary variable + + // NOTE: + // In the old matrix, the coordinate (m, n) is m*self->n + n + // We have to assign this to the coordinate (n, m) in the new + // matrix, i.e., to n*self->m + m (since the new matrix has self->m columns) + + // one-dimensional arrays can be transposed by simply swapping the dimensions + if((self->m != 1) && (self->n != 1)) { + uint8_t *c = (uint8_t *)self->array->items; + // self->bytes is the size of the bytearray, irrespective of the typecode + uint8_t *tmp = m_new(uint8_t, self->bytes); + for(size_t m=0; m < self->m; m++) { + for(size_t n=0; n < self->n; n++) { + memcpy(tmp+_sizeof*(n*self->m + m), c+_sizeof*(m*self->n + n), _sizeof); + } + } + memcpy(self->array->items, tmp, self->bytes); + m_del(uint8_t, tmp, self->bytes); + } + SWAP(size_t, self->m, self->n); + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_transpose_obj, ndarray_transpose); + +mp_obj_t ndarray_reshape(mp_obj_t self_in, mp_obj_t shape) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + if(!MP_OBJ_IS_TYPE(shape, &mp_type_tuple) || (MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(shape)) != 2)) { + mp_raise_ValueError(translate("shape must be a 2-tuple")); + } + + mp_obj_iter_buf_t iter_buf; + mp_obj_t item, iterable = mp_getiter(shape, &iter_buf); + uint16_t m, n; + item = mp_iternext(iterable); + m = mp_obj_get_int(item); + item = mp_iternext(iterable); + n = mp_obj_get_int(item); + if(m*n != self->m*self->n) { + // TODO: the proper error message would be "cannot reshape array of size %d into shape (%d, %d)" + mp_raise_ValueError(translate("cannot reshape array (incompatible input/output shape)")); + } + self->m = m; + self->n = n; + return MP_OBJ_FROM_PTR(self); +} + +MP_DEFINE_CONST_FUN_OBJ_2(ndarray_reshape_obj, ndarray_reshape); + +mp_int_t ndarray_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + // buffer_p.get_buffer() returns zero for success, while mp_get_buffer returns true for success + return !mp_get_buffer(self->array, bufinfo, flags); +} diff --git a/k210-freertos/mpy_support/standard_lib/ulab/ndarray.h b/k210-freertos/mpy_support/standard_lib/ulab/ndarray.h index c7fce67..b6cf62c 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/ndarray.h +++ b/k210-freertos/mpy_support/standard_lib/ulab/ndarray.h @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,9 +6,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #ifndef _NDARRAY_ #define _NDARRAY_ @@ -24,6 +25,12 @@ #define FLOAT_TYPECODE 'd' #endif +#if !CIRCUITPY +#define translate(x) x +#endif + +#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; } + extern const mp_obj_type_t ulab_ndarray_type; enum NDARRAY_TYPE { @@ -53,16 +60,30 @@ void ndarray_assign_elements(mp_obj_array_t *, mp_obj_t , uint8_t , size_t *); ndarray_obj_t *create_new_ndarray(size_t , size_t , uint8_t ); mp_obj_t ndarray_copy(mp_obj_t ); +#ifdef CIRCUITPY +mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args); +#else mp_obj_t ndarray_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *); +#endif mp_obj_t ndarray_subscr(mp_obj_t , mp_obj_t , mp_obj_t ); mp_obj_t ndarray_getiter(mp_obj_t , mp_obj_iter_buf_t *); mp_obj_t ndarray_binary_op(mp_binary_op_t , mp_obj_t , mp_obj_t ); mp_obj_t ndarray_unary_op(mp_unary_op_t , mp_obj_t ); mp_obj_t ndarray_shape(mp_obj_t ); -mp_obj_t ndarray_rawsize(mp_obj_t ); +mp_obj_t ndarray_size(mp_obj_t ); +mp_obj_t ndarray_itemsize(mp_obj_t ); mp_obj_t ndarray_flatten(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t ndarray_asbytearray(mp_obj_t ); + +mp_obj_t ndarray_reshape(mp_obj_t , mp_obj_t ); +MP_DECLARE_CONST_FUN_OBJ_2(ndarray_reshape_obj); + +mp_obj_t ndarray_transpose(mp_obj_t ); +MP_DECLARE_CONST_FUN_OBJ_1(ndarray_transpose_obj); + +mp_int_t ndarray_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); +//void ndarray_attributes(mp_obj_t , qstr , mp_obj_t *); + #define CREATE_SINGLE_ITEM(outarray, type, typecode, value) do {\ ndarray_obj_t *tmp = create_new_ndarray(1, 1, (typecode));\ diff --git a/k210-freertos/mpy_support/standard_lib/ulab/ndarray_properties.h b/k210-freertos/mpy_support/standard_lib/ulab/ndarray_properties.h new file mode 100644 index 0000000..a8f43cd --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/ulab/ndarray_properties.h @@ -0,0 +1,61 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020 Zoltán Vörös +*/ + +#ifndef _NDARRAY_PROPERTIES_ +#define _NDARRAY_PROPERTIES_ + +#include "py/runtime.h" +#include "py/binary.h" +#include "py/obj.h" +#include "py/objarray.h" + +#include "ndarray.h" + +#if CIRCUITPY +typedef struct _mp_obj_property_t { + mp_obj_base_t base; + mp_obj_t proxy[3]; // getter, setter, deleter +} mp_obj_property_t; + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_shape_obj, ndarray_shape); +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_size_obj, ndarray_size); +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_itemsize_obj, ndarray_itemsize); + +STATIC const mp_obj_property_t ndarray_shape_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ndarray_get_shape_obj, + mp_const_none, + mp_const_none }, +}; + +STATIC const mp_obj_property_t ndarray_size_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ndarray_get_size_obj, + mp_const_none, + mp_const_none }, +}; + +STATIC const mp_obj_property_t ndarray_itemsize_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ndarray_get_itemsize_obj, + mp_const_none, + mp_const_none }, +}; +#else + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_size_obj, ndarray_size); +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_itemsize_obj, ndarray_itemsize); +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape); + +#endif + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/numerical.c b/k210-freertos/mpy_support/standard_lib/ulab/numerical.c index 8fc80d7..a82221b 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/numerical.c +++ b/k210-freertos/mpy_support/standard_lib/ulab/numerical.c @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,9 +6,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #include #include #include @@ -18,6 +19,8 @@ #include "py/misc.h" #include "numerical.h" +#if ULAB_NUMERICAL_MODULE + enum NUMERICAL_FUNCTION_TYPE { NUMERICAL_MIN, NUMERICAL_MAX, @@ -28,56 +31,33 @@ enum NUMERICAL_FUNCTION_TYPE { NUMERICAL_STD, }; -mp_obj_t numerical_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, - { MP_QSTR_num, MP_ARG_INT, {.u_int = 50} }, - { MP_QSTR_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_true_obj)} }, - { MP_QSTR_retstep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, - { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - uint16_t len = args[2].u_int; - if(len < 2) { - mp_raise_ValueError("number of points must be at least 2"); - } - mp_float_t value, step; - value = mp_obj_get_float(args[0].u_obj); - uint8_t typecode = args[5].u_int; - if(args[3].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj)-value)/(len-1); - else step = (mp_obj_get_float(args[1].u_obj)-value)/len; - ndarray_obj_t *ndarray = create_new_ndarray(1, len, typecode); - if(typecode == NDARRAY_UINT8) { - uint8_t *array = (uint8_t *)ndarray->array->items; - for(size_t i=0; i < len; i++, value += step) array[i] = (uint8_t)value; - } else if(typecode == NDARRAY_INT8) { - int8_t *array = (int8_t *)ndarray->array->items; - for(size_t i=0; i < len; i++, value += step) array[i] = (int8_t)value; - } else if(typecode == NDARRAY_UINT16) { - uint16_t *array = (uint16_t *)ndarray->array->items; - for(size_t i=0; i < len; i++, value += step) array[i] = (uint16_t)value; - } else if(typecode == NDARRAY_INT16) { - int16_t *array = (int16_t *)ndarray->array->items; - for(size_t i=0; i < len; i++, value += step) array[i] = (int16_t)value; - } else { - mp_float_t *array = (mp_float_t *)ndarray->array->items; - for(size_t i=0; i < len; i++, value += step) array[i] = value; - } - if(args[4].u_obj == mp_const_false) { - return MP_OBJ_FROM_PTR(ndarray); - } else { - mp_obj_t tuple[2]; - tuple[0] = ndarray; - tuple[1] = mp_obj_new_float(step); - return mp_obj_new_tuple(2, tuple); - } +void axis_sorter(ndarray_obj_t *ndarray, mp_obj_t axis, size_t *m, size_t *n, size_t *N, + size_t *increment, size_t *len, size_t *start_inc) { + if(axis == mp_const_none) { // flatten the array + *m = 1; + *n = 1; + *len = ndarray->array->len; + *N = 1; + *increment = 1; + *start_inc = ndarray->array->len; + } else if((mp_obj_get_int(axis) == 1)) { // along the horizontal axis + *m = ndarray->m; + *n = 1; + *len = ndarray->n; + *N = ndarray->m; + *increment = 1; + *start_inc = ndarray->n; + } else { // along vertical axis + *m = 1; + *n = ndarray->n; + *len = ndarray->m; + *N = ndarray->n; + *increment = ndarray->n; + *start_inc = 1; + } } -mp_obj_t numerical_sum_mean_std_array(mp_obj_t oin, uint8_t optype) { +mp_obj_t numerical_sum_mean_std_iterable(mp_obj_t oin, uint8_t optype, size_t ddof) { mp_float_t value, sum = 0.0, sq_sum = 0.0; mp_obj_iter_buf_t iter_buf; mp_obj_t item, iterable = mp_getiter(oin, &iter_buf); @@ -85,233 +65,191 @@ mp_obj_t numerical_sum_mean_std_array(mp_obj_t oin, uint8_t optype) { while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { value = mp_obj_get_float(item); sum += value; - if(optype == NUMERICAL_STD) { - sq_sum += value*value; - } } if(optype == NUMERICAL_SUM) { return mp_obj_new_float(sum); } else if(optype == NUMERICAL_MEAN) { return mp_obj_new_float(sum/len); - } else { + } else { // this should be the case of the standard deviation + // TODO: note that we could get away with a single pass, if we used the Weldorf algorithm + // That should save a fair amount of time, because we would have to extract the values only once + iterable = mp_getiter(oin, &iter_buf); sum /= len; // this is now the mean! - return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(sq_sum/len-sum*sum)); + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + value = mp_obj_get_float(item) - sum; + sq_sum += value * value; + } + return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(sq_sum/(len-ddof))); } } -STATIC mp_float_t numerical_sum_mean_std_single_line(void *data, size_t start, size_t stop, - size_t stride, uint8_t typecode, uint8_t optype) { - - mp_float_t sum = 0.0, sq_sum = 0.0, value; - size_t len = 0; - for(size_t i=start; i < stop; i+=stride, len++) { - value = ndarray_get_float_value(data, typecode, i); - sum += value; - if(optype == NUMERICAL_STD) { - sq_sum += value*value; +STATIC mp_obj_t numerical_sum_mean_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype) { + size_t m, n, increment, start, start_inc, N, len; + axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc); + ndarray_obj_t *results = create_new_ndarray(m, n, NDARRAY_FLOAT); + mp_float_t sum, sq_sum; + mp_float_t *farray = (mp_float_t *)results->array->items; + for(size_t j=0; j < N; j++) { // result index + start = j * start_inc; + sum = sq_sum = 0.0; + if(ndarray->array->typecode == NDARRAY_UINT8) { + RUN_SUM(ndarray, uint8_t, optype, len, start, increment); + } else if(ndarray->array->typecode == NDARRAY_INT8) { + RUN_SUM(ndarray, int8_t, optype, len, start, increment); + } else if(ndarray->array->typecode == NDARRAY_UINT16) { + RUN_SUM(ndarray, uint16_t, optype, len, start, increment); + } else if(ndarray->array->typecode == NDARRAY_INT16) { + RUN_SUM(ndarray, int16_t, optype, len, start, increment); + } else { // this will be mp_float_t, no need to check + RUN_SUM(ndarray, mp_float_t, optype, len, start, increment); + } + if(optype == NUMERICAL_SUM) { + farray[j] = sum; + } else { // this is the case of the mean + farray[j] = sum / len; } } - if(len == 0) { - mp_raise_ValueError("data length is 0!"); - } - if(optype == NUMERICAL_SUM) { - return sum; - } else if(optype == NUMERICAL_MEAN) { - return sum/len; - } else { - sum /= len; // this is now the mean! - return MICROPY_FLOAT_C_FUN(sqrt)(sq_sum/len-sum*sum); + if(results->array->len == 1) { + return mp_obj_new_float(farray[0]); } + return MP_OBJ_FROM_PTR(results); } -STATIC mp_obj_t numerical_sum_mean_std_matrix(mp_obj_t oin, mp_obj_t axis, uint8_t optype) { - ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); - if((axis == mp_const_none) || (in->m == 1) || (in->n == 1)) { - // return the value for the flattened array - return mp_obj_new_float(numerical_sum_mean_std_single_line(in->array->items, 0, - in->array->len, 1, in->array->typecode, optype)); - } else { - uint8_t _axis = mp_obj_get_int(axis); - size_t m = (_axis == 0) ? 1 : in->m; - size_t n = (_axis == 0) ? in->n : 1; - size_t len = in->array->len; - mp_float_t sms; - // TODO: pass in->array->typcode to create_new_ndarray - ndarray_obj_t *out = create_new_ndarray(m, n, NDARRAY_FLOAT); - - // TODO: these two cases could probably be combined in a more elegant fashion... - if(_axis == 0) { // vertical - for(size_t i=0; i < n; i++) { - sms = numerical_sum_mean_std_single_line(in->array->items, i, len, - n, in->array->typecode, optype); - ((float_t *)out->array->items)[i] = sms; - } - } else { // horizontal - for(size_t i=0; i < m; i++) { - sms = numerical_sum_mean_std_single_line(in->array->items, i*in->n, - (i+1)*in->n, 1, in->array->typecode, optype); - ((float_t *)out->array->items)[i] = sms; - } +mp_obj_t numerical_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, size_t ddof) { + size_t m, n, increment, start, start_inc, N, len; + mp_float_t sum, sum_sq; + + axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc); + if(ddof > len) { + mp_raise_ValueError(translate("ddof must be smaller than length of data set")); + } + ndarray_obj_t *results = create_new_ndarray(m, n, NDARRAY_FLOAT); + mp_float_t *farray = (mp_float_t *)results->array->items; + for(size_t j=0; j < N; j++) { // result index + start = j * start_inc; + sum = 0.0; + sum_sq = 0.0; + if(ndarray->array->typecode == NDARRAY_UINT8) { + RUN_STD(ndarray, uint8_t, len, start, increment); + } else if(ndarray->array->typecode == NDARRAY_INT8) { + RUN_STD(ndarray, int8_t, len, start, increment); + } else if(ndarray->array->typecode == NDARRAY_UINT16) { + RUN_STD(ndarray, uint16_t, len, start, increment); + } else if(ndarray->array->typecode == NDARRAY_INT16) { + RUN_STD(ndarray, int16_t, len, start, increment); + } else { // this will be mp_float_t, no need to check + RUN_STD(ndarray, mp_float_t, len, start, increment); } - return MP_OBJ_FROM_PTR(out); + farray[j] = MICROPY_FLOAT_C_FUN(sqrt)(sum_sq/(len - ddof)); } + if(results->array->len == 1) { + return mp_obj_new_float(farray[0]); + } + return MP_OBJ_FROM_PTR(results); } -size_t numerical_argmin_argmax_array(ndarray_obj_t *in, size_t start, - size_t stop, size_t stride, uint8_t op) { - size_t best_idx = start; - if(in->array->typecode == NDARRAY_UINT8) { - ARG_MIN_LOOP(in, uint8_t, start, stop, stride, op); - } else if(in->array->typecode == NDARRAY_INT8) { - ARG_MIN_LOOP(in, int8_t, start, stop, stride, op); - } else if(in->array->typecode == NDARRAY_UINT16) { - ARG_MIN_LOOP(in, uint16_t, start, stop, stride, op); - } else if(in->array->typecode == NDARRAY_INT16) { - ARG_MIN_LOOP(in, uint16_t, start, stop, stride, op); - } else if(in->array->typecode == NDARRAY_FLOAT) { - ARG_MIN_LOOP(in, mp_float_t, start, stop, stride, op); +mp_obj_t numerical_argmin_argmax_iterable(mp_obj_t oin, mp_obj_t axis, uint8_t optype) { + size_t idx = 0, best_idx = 0; + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(oin, &iter_buf); + mp_obj_t best_obj = MP_OBJ_NULL; + mp_obj_t item; + mp_uint_t op = MP_BINARY_OP_LESS; + if((optype == NUMERICAL_ARGMAX) || (optype == NUMERICAL_MAX)) op = MP_BINARY_OP_MORE; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if ((best_obj == MP_OBJ_NULL) || (mp_binary_op(op, item, best_obj) == mp_const_true)) { + best_obj = item; + best_idx = idx; + } + idx++; } - return best_idx; + if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) { + return MP_OBJ_NEW_SMALL_INT(best_idx); + } else { + return best_obj; + } } -void copy_value_into_ndarray(ndarray_obj_t *target, ndarray_obj_t *source, size_t target_idx, size_t source_idx) { - // since we are simply copying, it doesn't matter, whether the arrays are signed or unsigned, - // we can cast them in any way we like - // This could also be done with byte copies. I don't know, whether that would have any benefits - if((target->array->typecode == NDARRAY_UINT8) || (target->array->typecode == NDARRAY_INT8)) { - ((uint8_t *)target->array->items)[target_idx] = ((uint8_t *)source->array->items)[source_idx]; - } else if((target->array->typecode == NDARRAY_UINT16) || (target->array->typecode == NDARRAY_INT16)) { - ((uint16_t *)target->array->items)[target_idx] = ((uint16_t *)source->array->items)[source_idx]; - } else { - ((float *)target->array->items)[target_idx] = ((float *)source->array->items)[source_idx]; +mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype) { + size_t m, n, increment, start, start_inc, N, len; + axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc); + ndarray_obj_t *results; + if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) { + // we could save some RAM by taking NDARRAY_UINT8, if the dimensions + // are smaller than 256, but the code would become more involving + // (we would also need extra flash space) + results = create_new_ndarray(m, n, NDARRAY_UINT16); + } else { + results = create_new_ndarray(m, n, ndarray->array->typecode); } -} - -STATIC mp_obj_t numerical_argmin_argmax(mp_obj_t oin, mp_obj_t axis, uint8_t optype) { - if(MP_OBJ_IS_TYPE(oin, &mp_type_tuple) || MP_OBJ_IS_TYPE(oin, &mp_type_list) || - MP_OBJ_IS_TYPE(oin, &mp_type_range)) { - // This case will work for single iterables only - size_t idx = 0, best_idx = 0; - mp_obj_iter_buf_t iter_buf; - mp_obj_t iterable = mp_getiter(oin, &iter_buf); - mp_obj_t best_obj = MP_OBJ_NULL; - mp_obj_t item; - mp_uint_t op = MP_BINARY_OP_LESS; - if((optype == NUMERICAL_ARGMAX) || (optype == NUMERICAL_MAX)) op = MP_BINARY_OP_MORE; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if ((best_obj == MP_OBJ_NULL) || (mp_binary_op(op, item, best_obj) == mp_const_true)) { - best_obj = item; - best_idx = idx; + + for(size_t j=0; j < N; j++) { // result index + start = j * start_inc; + if((ndarray->array->typecode == NDARRAY_UINT8) || (ndarray->array->typecode == NDARRAY_INT8)) { + if((optype == NUMERICAL_MAX) || (optype == NUMERICAL_MIN)) { + RUN_ARGMIN(ndarray, results, uint8_t, uint8_t, len, start, increment, optype, j); + } else { + RUN_ARGMIN(ndarray, results, uint8_t, uint16_t, len, start, increment, optype, j); } - idx++; - } - if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) { - return MP_OBJ_NEW_SMALL_INT(best_idx); + } else if((ndarray->array->typecode == NDARRAY_UINT16) || (ndarray->array->typecode == NDARRAY_INT16)) { + RUN_ARGMIN(ndarray, results, uint16_t, uint16_t, len, start, increment, optype, j); } else { - return best_obj; - } - } else if(mp_obj_is_type(oin, &ulab_ndarray_type)) { - ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); - size_t best_idx; - if((axis == mp_const_none) || (in->m == 1) || (in->n == 1)) { - // return the value for the flattened array - best_idx = numerical_argmin_argmax_array(in, 0, in->array->len, 1, optype); - if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) { - return MP_OBJ_NEW_SMALL_INT(best_idx); - } else { - if(in->array->typecode == NDARRAY_FLOAT) { - return mp_obj_new_float(ndarray_get_float_value(in->array->items, in->array->typecode, best_idx)); - } else { - return mp_binary_get_val_array(in->array->typecode, in->array->items, best_idx); - } - } - } else { // we have to work with a full matrix here - uint8_t _axis = mp_obj_get_int(axis); - size_t m = (_axis == 0) ? 1 : in->m; - size_t n = (_axis == 0) ? in->n : 1; - size_t len = in->array->len; - ndarray_obj_t *ndarray = NULL; - if((optype == NUMERICAL_MAX) || (optype == NUMERICAL_MIN)) { - ndarray = create_new_ndarray(m, n, in->array->typecode); - } else { // argmin/argmax - // TODO: one might get away with uint8_t, if both m, and n < 255 - ndarray = create_new_ndarray(m, n, NDARRAY_UINT16); - } - - // TODO: these two cases could probably be combined in a more elegant fashion... - if(_axis == 0) { // vertical - for(size_t i=0; i < n; i++) { - best_idx = numerical_argmin_argmax_array(in, i, len, n, optype); - if((optype == NUMERICAL_MIN) || (optype == NUMERICAL_MAX)) { - copy_value_into_ndarray(ndarray, in, i, best_idx); - } else { - ((uint16_t *)ndarray->array->items)[i] = (uint16_t)(best_idx / n); - } - } - } else { // horizontal - for(size_t i=0; i < m; i++) { - best_idx = numerical_argmin_argmax_array(in, i*in->n, (i+1)*in->n, 1, optype); - if((optype == NUMERICAL_MIN) || (optype == NUMERICAL_MAX)) { - copy_value_into_ndarray(ndarray, in, i, best_idx); - } else { - ((uint16_t *)ndarray->array->items)[i] = (uint16_t)(best_idx - i*in->n); - } - } - } - return MP_OBJ_FROM_PTR(ndarray); + if((optype == NUMERICAL_MAX) || (optype == NUMERICAL_MIN)) { + RUN_ARGMIN(ndarray, results, mp_float_t, mp_float_t, len, start, increment, optype, j); + } else { + RUN_ARGMIN(ndarray, results, mp_float_t, uint16_t, len, start, increment, optype, j); } - return mp_const_none; } - mp_raise_TypeError("input type is not supported"); + } + return MP_OBJ_FROM_PTR(results); } -STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t type) { +STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t optype) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} } , - { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} } , + { MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t oin = args[0].u_obj; mp_obj_t axis = args[1].u_obj; if((axis != mp_const_none) && (mp_obj_get_int(axis) != 0) && (mp_obj_get_int(axis) != 1)) { // this seems to pass with False, and True... - mp_raise_ValueError("axis must be None, 0, or 1"); + mp_raise_ValueError(translate("axis must be None, 0, or 1")); } if(MP_OBJ_IS_TYPE(oin, &mp_type_tuple) || MP_OBJ_IS_TYPE(oin, &mp_type_list) || MP_OBJ_IS_TYPE(oin, &mp_type_range)) { - switch(type) { + switch(optype) { case NUMERICAL_MIN: case NUMERICAL_ARGMIN: case NUMERICAL_MAX: case NUMERICAL_ARGMAX: - return numerical_argmin_argmax(oin, axis, type); + return numerical_argmin_argmax_iterable(oin, axis, optype); case NUMERICAL_SUM: case NUMERICAL_MEAN: - case NUMERICAL_STD: - return numerical_sum_mean_std_array(oin, type); + return numerical_sum_mean_std_iterable(oin, optype, 0); default: // we should never reach this point, but whatever return mp_const_none; } } else if(MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { - switch(type) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin); + switch(optype) { case NUMERICAL_MIN: case NUMERICAL_MAX: case NUMERICAL_ARGMIN: case NUMERICAL_ARGMAX: - return numerical_argmin_argmax(oin, axis, type); + return numerical_argmin_argmax_ndarray(ndarray, axis, optype); case NUMERICAL_SUM: case NUMERICAL_MEAN: - case NUMERICAL_STD: - return numerical_sum_mean_std_matrix(oin, axis, type); + return numerical_sum_mean_ndarray(ndarray, axis, optype); default: - mp_raise_NotImplementedError("operation is not implemented on ndarrays"); + mp_raise_NotImplementedError(translate("operation is not implemented on ndarrays")); } } else { - mp_raise_TypeError("input must be tuple, list, range, or ndarray"); + mp_raise_TypeError(translate("input must be tuple, list, range, or ndarray")); } return mp_const_none; } @@ -320,35 +258,73 @@ mp_obj_t numerical_min(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MIN); } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min); + mp_obj_t numerical_max(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MAX); } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_max_obj, 1, numerical_max); + mp_obj_t numerical_argmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMIN); } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin); + mp_obj_t numerical_argmax(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMAX); } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmax_obj, 1, numerical_argmax); + mp_obj_t numerical_sum(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return numerical_function(n_args, pos_args, kw_args, NUMERICAL_SUM); } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sum_obj, 1, numerical_sum); + mp_obj_t numerical_mean(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MEAN); } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean); + mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - return numerical_function(n_args, pos_args, kw_args, NUMERICAL_STD); + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } } , + { MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_ddof, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t oin = args[0].u_obj; + mp_obj_t axis = args[1].u_obj; + size_t ddof = args[2].u_int; + if((axis != mp_const_none) && (mp_obj_get_int(axis) != 0) && (mp_obj_get_int(axis) != 1)) { + // this seems to pass with False, and True... + mp_raise_ValueError(translate("axis must be None, 0, or 1")); + } + if(MP_OBJ_IS_TYPE(oin, &mp_type_tuple) || MP_OBJ_IS_TYPE(oin, &mp_type_list) || MP_OBJ_IS_TYPE(oin, &mp_type_range)) { + return numerical_sum_mean_std_iterable(oin, NUMERICAL_STD, ddof); + } else if(MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin); + return numerical_std_ndarray(ndarray, axis, ddof); + } else { + mp_raise_TypeError(translate("input must be tuple, list, range, or ndarray")); + } + return mp_const_none; } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std); + mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, - { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -359,7 +335,7 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar if((args[2].u_obj != mp_const_none) && (mp_obj_get_int(args[2].u_obj) != 0) && (mp_obj_get_int(args[2].u_obj) != 1)) { - mp_raise_ValueError("axis must be None, 0, or 1"); + mp_raise_ValueError(translate("axis must be None, 0, or 1")); } ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); @@ -424,22 +400,24 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar } } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll); + mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, - { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { - mp_raise_TypeError("flip argument must be an ndarray"); + if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("flip argument must be an ndarray")); } if((args[1].u_obj != mp_const_none) && (mp_obj_get_int(args[1].u_obj) != 0) && (mp_obj_get_int(args[1].u_obj) != 1)) { - mp_raise_ValueError("axis must be None, 0, or 1"); + mp_raise_ValueError(translate("axis must be None, 0, or 1")); } ndarray_obj_t *in = MP_OBJ_TO_PTR(args[0].u_obj); @@ -471,9 +449,11 @@ mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar return out; } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip); + mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_n, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1 } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 } }, }; @@ -481,8 +461,8 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { - mp_raise_TypeError("diff argument must be an ndarray"); + if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("diff argument must be an ndarray")); } ndarray_obj_t *in = MP_OBJ_TO_PTR(args[0].u_obj); @@ -492,10 +472,10 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar } else if(args[2].u_int == 0) { // differtiate along vertical axis increment = in->n; } else { - mp_raise_ValueError("axis must be -1, 0, or 1"); + mp_raise_ValueError(translate("axis must be -1, 0, or 1")); } if((args[1].u_int < 0) || (args[1].u_int > 9)) { - mp_raise_ValueError("n must be between 0, and 9"); + mp_raise_ValueError(translate("n must be between 0, and 9")); } uint8_t n = args[1].u_int; int8_t *stencil = m_new(int8_t, n+1); @@ -539,9 +519,11 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar return MP_OBJ_FROM_PTR(out); } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff); + mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) { - if(!mp_obj_is_type(oin, &ulab_ndarray_type)) { - mp_raise_TypeError("sort argument must be an ndarray"); + if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("sort argument must be an ndarray")); } ndarray_obj_t *ndarray; @@ -572,7 +554,7 @@ mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) { end = ndarray->m; N = ndarray->m; } else { - mp_raise_ValueError("axis must be -1, 0, None, or 1"); + mp_raise_ValueError(translate("axis must be -1, 0, None, or 1")); } size_t q, k, p, c; @@ -598,7 +580,7 @@ mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) { // numpy function mp_obj_t numerical_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } }, }; @@ -607,10 +589,13 @@ mp_obj_t numerical_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 0); } + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort); + // method of an ndarray mp_obj_t numerical_sort_inplace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } }, }; @@ -620,15 +605,17 @@ mp_obj_t numerical_sort_inplace(size_t n_args, const mp_obj_t *pos_args, mp_map_ return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 1); } +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace); + mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj) } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { - mp_raise_TypeError("argsort argument must be an ndarray"); + if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("argsort argument must be an ndarray")); } ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); @@ -658,7 +645,7 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw end = m; N = m; } else { - mp_raise_ValueError("axis must be -1, 0, None, or 1"); + mp_raise_ValueError(translate("axis must be -1, 0, None, or 1")); } // at the expense of flash, we could save RAM by creating @@ -689,3 +676,30 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw } return MP_OBJ_FROM_PTR(indices); } + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort); + +STATIC const mp_rom_map_elem_t ulab_numerical_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_numerical) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&numerical_sum_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&numerical_mean_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_std), (mp_obj_t)&numerical_std_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_min), (mp_obj_t)&numerical_min_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_max), (mp_obj_t)&numerical_max_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_argmin), (mp_obj_t)&numerical_argmin_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_argmax), (mp_obj_t)&numerical_argmax_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_roll), (mp_obj_t)&numerical_roll_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_flip), (mp_obj_t)&numerical_flip_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_diff), (mp_obj_t)&numerical_diff_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sort), (mp_obj_t)&numerical_sort_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_argsort), (mp_obj_t)&numerical_argsort_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_numerical_globals, ulab_numerical_globals_table); + +mp_obj_module_t ulab_numerical_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_numerical_globals, +}; + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/numerical.h b/k210-freertos/mpy_support/standard_lib/ulab/numerical.h index a59f538..e69bfc1 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/numerical.h +++ b/k210-freertos/mpy_support/standard_lib/ulab/numerical.h @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,47 +6,62 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #ifndef _NUMERICAL_ #define _NUMERICAL_ +#include "ulab.h" #include "ndarray.h" -mp_obj_t numerical_linspace(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_sum(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_mean(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_std(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_min(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_max(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_argmin(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_argmax(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_roll(size_t , const mp_obj_t *, mp_map_t *); +#if ULAB_NUMERICAL_MODULE + +extern mp_obj_module_t ulab_numerical_module; // TODO: implement minimum/maximum, and cumsum -mp_obj_t numerical_minimum(mp_obj_t , mp_obj_t ); -mp_obj_t numerical_maximum(mp_obj_t , mp_obj_t ); -mp_obj_t numerical_cumsum(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_flip(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_diff(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_sort(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_sort_inplace(size_t , const mp_obj_t *, mp_map_t *); -mp_obj_t numerical_argsort(size_t , const mp_obj_t *, mp_map_t *); +//mp_obj_t numerical_minimum(mp_obj_t , mp_obj_t ); +//mp_obj_t numerical_maximum(mp_obj_t , mp_obj_t ); +//mp_obj_t numerical_cumsum(size_t , const mp_obj_t *, mp_map_t *); -// this macro could be tighter, if we moved the ifs to the argmin function, assigned <, as well as > -#define ARG_MIN_LOOP(in, type, start, stop, stride, op) do {\ - type *array = (type *)(in)->array->items;\ +#define RUN_ARGMIN(in, out, typein, typeout, len, start, increment, op, pos) do {\ + typein *array = (typein *)(in)->array->items;\ + typeout *outarray = (typeout *)(out)->array->items;\ + size_t best_index = 0;\ if(((op) == NUMERICAL_MAX) || ((op) == NUMERICAL_ARGMAX)) {\ - for(size_t i=(start)+(stride); i < (stop); i+=(stride)) {\ - if((array)[i] > (array)[best_idx]) {\ - best_idx = i;\ - }\ + for(size_t i=1; i < (len); i++) {\ + if(array[(start)+i*(increment)] > array[(start)+best_index*(increment)]) best_index = i;\ }\ + if((op) == NUMERICAL_MAX) outarray[(pos)] = array[(start)+best_index*(increment)];\ + else outarray[(pos)] = best_index;\ } else{\ - for(size_t i=(start)+(stride); i < (stop); i+=(stride)) {\ - if((array)[i] < (array)[best_idx]) best_idx = i;\ + for(size_t i=1; i < (len); i++) {\ + if(array[(start)+i*(increment)] < array[(start)+best_index*(increment)]) best_index = i;\ }\ + if((op) == NUMERICAL_MIN) outarray[(pos)] = array[(start)+best_index*(increment)];\ + else outarray[(pos)] = best_index;\ + }\ +} while(0) + +#define RUN_SUM(ndarray, type, optype, len, start, increment) do {\ + type *array = (type *)(ndarray)->array->items;\ + type value;\ + for(size_t j=0; j < (len); j++) {\ + value = array[(start)+j*(increment)];\ + sum += value;\ + }\ +} while(0) + +#define RUN_STD(ndarray, type, len, start, increment) do {\ + type *array = (type *)(ndarray)->array->items;\ + mp_float_t value;\ + for(size_t j=0; j < (len); j++) {\ + sum += array[(start)+j*(increment)];\ + }\ + sum /= (len);\ + for(size_t j=0; j < (len); j++) {\ + value = (array[(start)+j*(increment)] - sum);\ + sum_sq += value * value;\ }\ } while(0) @@ -132,4 +148,19 @@ mp_obj_t numerical_argsort(size_t , const mp_obj_t *, mp_map_t *); }\ } while(0) +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_min_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_max_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmin_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmax_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sum_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_mean_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_std_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_roll_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_flip_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_diff_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sort_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argsort_obj); + +#endif #endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/poly.c b/k210-freertos/mpy_support/standard_lib/ulab/poly.c index 97bb227..03dcca0 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/poly.c +++ b/k210-freertos/mpy_support/standard_lib/ulab/poly.c @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,9 +6,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #include "py/obj.h" #include "py/runtime.h" #include "py/objarray.h" @@ -15,19 +16,19 @@ #include "linalg.h" #include "poly.h" - +#if ULAB_POLY_MODULE bool object_is_nditerable(mp_obj_t o_in) { - if(mp_obj_is_type(o_in, &ulab_ndarray_type) || - mp_obj_is_type(o_in, &mp_type_tuple) || - mp_obj_is_type(o_in, &mp_type_list) || - mp_obj_is_type(o_in, &mp_type_range)) { + if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type) || + MP_OBJ_IS_TYPE(o_in, &mp_type_tuple) || + MP_OBJ_IS_TYPE(o_in, &mp_type_list) || + MP_OBJ_IS_TYPE(o_in, &mp_type_range)) { return true; } return false; } size_t get_nditerable_len(mp_obj_t o_in) { - if(mp_obj_is_type(o_in, &ulab_ndarray_type)) { + if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) { ndarray_obj_t *in = MP_OBJ_TO_PTR(o_in); return in->array->len; } else { @@ -82,12 +83,14 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) { return MP_OBJ_FROM_PTR(out); } +MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval); + mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) { if((n_args != 2) && (n_args != 3)) { - mp_raise_ValueError("number of arguments must be 2, or 3"); + mp_raise_ValueError(translate("number of arguments must be 2, or 3")); } if(!object_is_nditerable(args[0])) { - mp_raise_ValueError("input data must be an iterable"); + mp_raise_ValueError(translate("input data must be an iterable")); } uint16_t lenx = 0, leny = 0; uint8_t deg = 0; @@ -99,7 +102,7 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) { leny = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); deg = (uint8_t)mp_obj_get_int(args[1]); if(leny < deg) { - mp_raise_ValueError("more degrees of freedom than data points"); + mp_raise_ValueError(translate("more degrees of freedom than data points")); } lenx = leny; x = m_new(mp_float_t, lenx); // assume uniformly spaced data points @@ -112,11 +115,11 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) { lenx = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); leny = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); if(lenx != leny) { - mp_raise_ValueError("input vectors must be of equal length"); + mp_raise_ValueError(translate("input vectors must be of equal length")); } deg = (uint8_t)mp_obj_get_int(args[2]); if(leny < deg) { - mp_raise_ValueError("more degrees of freedom than data points"); + mp_raise_ValueError(translate("more degrees of freedom than data points")); } x = m_new(mp_float_t, lenx); fill_array_iterable(x, args[0]); @@ -156,7 +159,7 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) { m_del(mp_float_t, x, lenx); m_del(mp_float_t, y, lenx); m_del(mp_float_t, prod, (deg+1)*(deg+1)); - mp_raise_ValueError("could not invert Vandermonde matrix"); + mp_raise_ValueError(translate("could not invert Vandermonde matrix")); } // at this point, we have the inverse of X^T * X // y is a column vector; x is free now, we can use it for storing intermediate values @@ -191,3 +194,20 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) { } return MP_OBJ_FROM_PTR(beta); } + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit); + +STATIC const mp_rom_map_elem_t ulab_poly_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_poly) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_polyval), (mp_obj_t)&poly_polyval_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_polyfit), (mp_obj_t)&poly_polyfit_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_poly_globals, ulab_poly_globals_table); + +mp_obj_module_t ulab_poly_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_poly_globals, +}; + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/poly.h b/k210-freertos/mpy_support/standard_lib/ulab/poly.h index 28f8771..59a774b 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/poly.h +++ b/k210-freertos/mpy_support/standard_lib/ulab/poly.h @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,13 +6,20 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #ifndef _POLY_ #define _POLY_ -mp_obj_t poly_polyval(mp_obj_t , mp_obj_t ); -mp_obj_t poly_polyfit(size_t , const mp_obj_t *); +#include "ulab.h" + +#if ULAB_POLY_MODULE +extern mp_obj_module_t ulab_poly_module; + +MP_DECLARE_CONST_FUN_OBJ_2(poly_polyval_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj); + +#endif #endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/ulab.c b/k210-freertos/mpy_support/standard_lib/ulab/ulab.c index 4cb31b0..ad56be7 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/ulab.c +++ b/k210-freertos/mpy_support/standard_lib/ulab/ulab.c @@ -1,13 +1,14 @@ + /* - * This file is part of the micropython-ulab project, + * This file is part of the micropython-ulab project, * * https://github.com/v923z/micropython-ulab * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #include #include #include @@ -17,92 +18,32 @@ #include "py/obj.h" #include "py/objarray.h" +#include "ulab.h" #include "ndarray.h" +#include "ndarray_properties.h" +#include "create.h" #include "linalg.h" #include "vectorise.h" #include "poly.h" #include "fft.h" +#include "filter.h" #include "numerical.h" +#include "extras.h" -#define ULAB_VERSION 0.262 - -typedef struct _mp_obj_float_t { - mp_obj_base_t base; - mp_float_t value; -} mp_obj_float_t; +STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, "0.37.0"); -mp_obj_float_t ulab_version = {{&mp_type_float}, ULAB_VERSION}; - -MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape); -MP_DEFINE_CONST_FUN_OBJ_1(ndarray_rawsize_obj, ndarray_rawsize); MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_flatten_obj, 1, ndarray_flatten); -MP_DEFINE_CONST_FUN_OBJ_1(ndarray_asbytearray_obj, ndarray_asbytearray); - -MP_DEFINE_CONST_FUN_OBJ_1(linalg_transpose_obj, linalg_transpose); -MP_DEFINE_CONST_FUN_OBJ_2(linalg_reshape_obj, linalg_reshape); -MP_DEFINE_CONST_FUN_OBJ_KW(linalg_size_obj, 1, linalg_size); -MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv); -MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot); -MP_DEFINE_CONST_FUN_OBJ_KW(linalg_zeros_obj, 0, linalg_zeros); -MP_DEFINE_CONST_FUN_OBJ_KW(linalg_ones_obj, 0, linalg_ones); -MP_DEFINE_CONST_FUN_OBJ_KW(linalg_eye_obj, 0, linalg_eye); -MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det); -MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig); - -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asin_obj, vectorise_asin); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asinh_obj, vectorise_asinh); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atan_obj, vectorise_atan); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atanh_obj, vectorise_atanh); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_ceil_obj, vectorise_ceil); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cos_obj, vectorise_cos); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erf_obj, vectorise_erf); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erfc_obj, vectorise_erfc); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_exp_obj, vectorise_exp); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_expm1_obj, vectorise_expm1); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_floor_obj, vectorise_floor); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_gamma_obj, vectorise_gamma); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_lgamma_obj, vectorise_lgamma); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log_obj, vectorise_log); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log10_obj, vectorise_log10); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log2_obj, vectorise_log2); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sin_obj, vectorise_sin); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sinh_obj, vectorise_sinh); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sqrt_obj, vectorise_sqrt); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan); -MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh); - -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_linspace_obj, 2, numerical_linspace); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sum_obj, 1, numerical_sum); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_max_obj, 1, numerical_max); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmax_obj, 1, numerical_argmax); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace); -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort); - -STATIC MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit); - -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj, 1, 2, fft_spectrum); STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&ndarray_reshape_obj) }, + { MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&ndarray_transpose_obj) }, + { MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_obj) }, { MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ndarray_shape_obj) }, - { MP_ROM_QSTR(MP_QSTR_rawsize), MP_ROM_PTR(&ndarray_rawsize_obj) }, - { MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_obj) }, - { MP_ROM_QSTR(MP_QSTR_asbytearray), MP_ROM_PTR(&ndarray_asbytearray_obj) }, - { MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&linalg_transpose_obj) }, - { MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&linalg_reshape_obj) }, + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&ndarray_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_itemsize), MP_ROM_PTR(&ndarray_itemsize_obj) }, +#if CIRCUITPY { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) }, +#endif }; STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table); @@ -116,62 +57,39 @@ const mp_obj_type_t ulab_ndarray_type = { .getiter = ndarray_getiter, .unary_op = ndarray_unary_op, .binary_op = ndarray_binary_op, + .buffer_p = { .get_buffer = ndarray_get_buffer, }, .locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict, }; STATIC const mp_map_elem_t ulab_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) }, - { MP_ROM_QSTR(MP_QSTR___version__), MP_ROM_PTR(&ulab_version) }, + { MP_ROM_QSTR(MP_QSTR___version__), MP_ROM_PTR(&ulab_version_obj) }, { MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&ulab_ndarray_type }, - { MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&linalg_size_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj }, - { MP_ROM_QSTR(MP_QSTR_dot), (mp_obj_t)&linalg_dot_obj }, - { MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&linalg_zeros_obj }, - { MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&linalg_ones_obj }, - { MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&linalg_eye_obj }, - { MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj }, - { MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&vectorise_acos_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&vectorise_acosh_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&vectorise_asin_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&vectorise_asinh_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&vectorise_atan_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_atanh), (mp_obj_t)&vectorise_atanh_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ceil), (mp_obj_t)&vectorise_ceil_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_cos), (mp_obj_t)&vectorise_cos_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_erf), (mp_obj_t)&vectorise_erf_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_erfc), (mp_obj_t)&vectorise_erfc_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_exp), (mp_obj_t)&vectorise_exp_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_expm1), (mp_obj_t)&vectorise_expm1_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&vectorise_floor_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_gamma), (mp_obj_t)&vectorise_gamma_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_lgamma), (mp_obj_t)&vectorise_lgamma_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_log), (mp_obj_t)&vectorise_log_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_log10), (mp_obj_t)&vectorise_log10_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_log2), (mp_obj_t)&vectorise_log2_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sin), (mp_obj_t)&vectorise_sin_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sinh), (mp_obj_t)&vectorise_sinh_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sqrt), (mp_obj_t)&vectorise_sqrt_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_tan), (mp_obj_t)&vectorise_tan_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&vectorise_tanh_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_linspace), (mp_obj_t)&numerical_linspace_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&numerical_sum_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&numerical_mean_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_std), (mp_obj_t)&numerical_std_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_min), (mp_obj_t)&numerical_min_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_max), (mp_obj_t)&numerical_max_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_argmin), (mp_obj_t)&numerical_argmin_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_argmax), (mp_obj_t)&numerical_argmax_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_roll), (mp_obj_t)&numerical_roll_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_flip), (mp_obj_t)&numerical_flip_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_diff), (mp_obj_t)&numerical_diff_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sort), (mp_obj_t)&numerical_sort_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_argsort), (mp_obj_t)&numerical_argsort_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_polyval), (mp_obj_t)&poly_polyval_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_polyfit), (mp_obj_t)&poly_polyfit_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_fft), (mp_obj_t)&fft_fft_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ifft), (mp_obj_t)&fft_ifft_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_spectrum), (mp_obj_t)&fft_spectrum_obj }, + { MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&create_zeros_obj }, + { MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&create_ones_obj }, + { MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&create_eye_obj }, + { MP_ROM_QSTR(MP_QSTR_linspace), (mp_obj_t)&create_linspace_obj }, + #if ULAB_LINALG_MODULE + { MP_ROM_QSTR(MP_QSTR_linalg), MP_ROM_PTR(&ulab_linalg_module) }, + #endif + #if ULAB_VECTORISE_MODULE + { MP_ROM_QSTR(MP_QSTR_vector), MP_ROM_PTR(&ulab_vectorise_module) }, + #endif + #if ULAB_NUMERICAL_MODULE + { MP_ROM_QSTR(MP_QSTR_numerical), MP_ROM_PTR(&ulab_numerical_module) }, + #endif + #if ULAB_POLY_MODULE + { MP_ROM_QSTR(MP_QSTR_poly), MP_ROM_PTR(&ulab_poly_module) }, + #endif + #if ULAB_FFT_MODULE + { MP_ROM_QSTR(MP_QSTR_fft), MP_ROM_PTR(&ulab_fft_module) }, + #endif + #if ULAB_FILTER_MODULE + { MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&ulab_filter_module) }, + #endif + #if ULAB_EXTRAS_MODULE + { MP_ROM_QSTR(MP_QSTR_extras), MP_ROM_PTR(&ulab_extras_module) }, + #endif // class constants { MP_ROM_QSTR(MP_QSTR_uint8), MP_ROM_INT(NDARRAY_UINT8) }, { MP_ROM_QSTR(MP_QSTR_int8), MP_ROM_INT(NDARRAY_INT8) }, @@ -185,7 +103,7 @@ STATIC MP_DEFINE_CONST_DICT ( ulab_globals_table ); -const mp_obj_module_t ulab_user_cmodule = { +mp_obj_module_t ulab_user_cmodule = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_ulab_globals, }; diff --git a/k210-freertos/mpy_support/standard_lib/ulab/ulab.h b/k210-freertos/mpy_support/standard_lib/ulab/ulab.h new file mode 100644 index 0000000..57a499b --- /dev/null +++ b/k210-freertos/mpy_support/standard_lib/ulab/ulab.h @@ -0,0 +1,39 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Zoltán Vörös +*/ + +#ifndef __ULAB__ +#define __ULAB__ + +// create +#define ULAB_CREATE_MODULE (1) + +// vectorise (all functions) takes approx. 3 kB of flash space +#define ULAB_VECTORISE_MODULE (1) + +// linalg adds around 6 kB +#define ULAB_LINALG_MODULE (1) + +// poly is approx. 2.5 kB +#define ULAB_POLY_MODULE (1) + +// numerical is about 12 kB +#define ULAB_NUMERICAL_MODULE (1) + +// FFT costs about 2 kB of flash space +#define ULAB_FFT_MODULE (1) + +// the filter module takes about 1 kB of flash space +#define ULAB_FILTER_MODULE (1) + +// user-defined modules +#define ULAB_EXTRAS_MODULE (1) + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/vectorise.c b/k210-freertos/mpy_support/standard_lib/ulab/vectorise.c index 703754c..43db4a7 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/vectorise.c +++ b/k210-freertos/mpy_support/standard_lib/ulab/vectorise.c @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,9 +6,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #include #include #include @@ -21,9 +22,10 @@ #define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) #endif +#if ULAB_VECTORISE_MODULE mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) { // Return a single value, if o_in is not iterable - if(mp_obj_is_float(o_in) || mp_obj_is_integer(o_in)) { + if(mp_obj_is_float(o_in) || MP_OBJ_IS_INT(o_in)) { return mp_obj_new_float(f(mp_obj_get_float(o_in))); } mp_float_t x; @@ -60,26 +62,111 @@ mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) { return mp_const_none; } + MATH_FUN_1(acos, acos); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos); + MATH_FUN_1(acosh, acosh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh); + MATH_FUN_1(asin, asin); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asin_obj, vectorise_asin); + MATH_FUN_1(asinh, asinh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asinh_obj, vectorise_asinh); + MATH_FUN_1(atan, atan); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atan_obj, vectorise_atan); + MATH_FUN_1(atanh, atanh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atanh_obj, vectorise_atanh); + MATH_FUN_1(ceil, ceil); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_ceil_obj, vectorise_ceil); + MATH_FUN_1(cos, cos); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cos_obj, vectorise_cos); + +MATH_FUN_1(cosh, cosh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cosh_obj, vectorise_cosh); + MATH_FUN_1(erf, erf); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erf_obj, vectorise_erf); + MATH_FUN_1(erfc, erfc); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erfc_obj, vectorise_erfc); + MATH_FUN_1(exp, exp); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_exp_obj, vectorise_exp); + MATH_FUN_1(expm1, expm1); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_expm1_obj, vectorise_expm1); + MATH_FUN_1(floor, floor); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_floor_obj, vectorise_floor); + MATH_FUN_1(gamma, tgamma); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_gamma_obj, vectorise_gamma); + MATH_FUN_1(lgamma, lgamma); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_lgamma_obj, vectorise_lgamma); + MATH_FUN_1(log, log); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log_obj, vectorise_log); + MATH_FUN_1(log10, log10); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log10_obj, vectorise_log10); + MATH_FUN_1(log2, log2); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log2_obj, vectorise_log2); + MATH_FUN_1(sin, sin); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sin_obj, vectorise_sin); + MATH_FUN_1(sinh, sinh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sinh_obj, vectorise_sinh); + MATH_FUN_1(sqrt, sqrt); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sqrt_obj, vectorise_sqrt); + MATH_FUN_1(tan, tan); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan); + MATH_FUN_1(tanh, tanh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh); + +STATIC const mp_rom_map_elem_t ulab_vectorise_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_vector) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&vectorise_acos_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&vectorise_acosh_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&vectorise_asin_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&vectorise_asinh_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&vectorise_atan_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_atanh), (mp_obj_t)&vectorise_atanh_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ceil), (mp_obj_t)&vectorise_ceil_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_cos), (mp_obj_t)&vectorise_cos_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_erf), (mp_obj_t)&vectorise_erf_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_erfc), (mp_obj_t)&vectorise_erfc_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_exp), (mp_obj_t)&vectorise_exp_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_expm1), (mp_obj_t)&vectorise_expm1_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&vectorise_floor_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_gamma), (mp_obj_t)&vectorise_gamma_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_lgamma), (mp_obj_t)&vectorise_lgamma_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_log), (mp_obj_t)&vectorise_log_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_log10), (mp_obj_t)&vectorise_log10_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_log2), (mp_obj_t)&vectorise_log2_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sin), (mp_obj_t)&vectorise_sin_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sinh), (mp_obj_t)&vectorise_sinh_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sqrt), (mp_obj_t)&vectorise_sqrt_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_tan), (mp_obj_t)&vectorise_tan_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&vectorise_tanh_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_vectorise_globals, ulab_vectorise_globals_table); + +mp_obj_module_t ulab_vectorise_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_vectorise_globals, +}; + +#endif diff --git a/k210-freertos/mpy_support/standard_lib/ulab/vectorise.h b/k210-freertos/mpy_support/standard_lib/ulab/vectorise.h index d2beaff..a64402b 100644 --- a/k210-freertos/mpy_support/standard_lib/ulab/vectorise.h +++ b/k210-freertos/mpy_support/standard_lib/ulab/vectorise.h @@ -1,3 +1,4 @@ + /* * This file is part of the micropython-ulab project, * @@ -5,37 +6,18 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Zoltán Vörös + * Copyright (c) 2019-2020 Zoltán Vörös */ - + #ifndef _VECTORISE_ #define _VECTORISE_ +#include "ulab.h" #include "ndarray.h" -mp_obj_t vectorise_acos(mp_obj_t ); -mp_obj_t vectorise_acosh(mp_obj_t ); -mp_obj_t vectorise_asin(mp_obj_t ); -mp_obj_t vectorise_asinh(mp_obj_t ); -mp_obj_t vectorise_atan(mp_obj_t ); -mp_obj_t vectorise_atanh(mp_obj_t ); -mp_obj_t vectorise_ceil(mp_obj_t ); -mp_obj_t vectorise_cos(mp_obj_t ); -mp_obj_t vectorise_erf(mp_obj_t ); -mp_obj_t vectorise_erfc(mp_obj_t ); -mp_obj_t vectorise_exp(mp_obj_t ); -mp_obj_t vectorise_expm1(mp_obj_t ); -mp_obj_t vectorise_floor(mp_obj_t ); -mp_obj_t vectorise_gamma(mp_obj_t ); -mp_obj_t vectorise_lgamma(mp_obj_t ); -mp_obj_t vectorise_log(mp_obj_t ); -mp_obj_t vectorise_log10(mp_obj_t ); -mp_obj_t vectorise_log2(mp_obj_t ); -mp_obj_t vectorise_sin(mp_obj_t ); -mp_obj_t vectorise_sinh(mp_obj_t ); -mp_obj_t vectorise_sqrt(mp_obj_t ); -mp_obj_t vectorise_tan(mp_obj_t ); -mp_obj_t vectorise_tanh(mp_obj_t ); +#if ULAB_VECTORISE_MODULE + +mp_obj_module_t ulab_vectorise_module; #define ITERATE_VECTOR(type, source, out) do {\ type *input = (type *)(source)->array->items;\ @@ -47,6 +29,7 @@ mp_obj_t vectorise_tanh(mp_obj_t ); #define MATH_FUN_1(py_name, c_name) \ mp_obj_t vectorise_ ## py_name(mp_obj_t x_obj) { \ return vectorise_generic_vector(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \ - } +} #endif +#endif diff --git a/k210-freertos/mpy_support/standard_lib/uos/littleflash.c b/k210-freertos/mpy_support/standard_lib/uos/littleflash.c index 271b1ff..058e78d 100644 --- a/k210-freertos/mpy_support/standard_lib/uos/littleflash.c +++ b/k210-freertos/mpy_support/standard_lib/uos/littleflash.c @@ -897,7 +897,9 @@ static int _cb_traverse(void *data, lfs_block_t block) STATIC mp_obj_t vfs_littlefs_trim(size_t n_args, const mp_obj_t *args) { bool do_erase = false; + bool do_print = true; if (n_args > 0) do_erase = mp_obj_is_true(args[0]); + if (n_args > 1) do_print = mp_obj_is_true(args[1]); uint8_t lfs_blocks[LITTLEFS_CFG_PHYS_SZ / LITTLEFS_CFG_SECTOR_SIZE / 8]; memset(lfs_blocks, 0, LITTLEFS_CFG_PHYS_SZ / LITTLEFS_CFG_SECTOR_SIZE / 8); @@ -907,6 +909,8 @@ STATIC mp_obj_t vfs_littlefs_trim(size_t n_args, const mp_obj_t *args) uint32_t bused=0, bfree=0; uint32_t sect_erase=0, blocks_erase=0, sect_erased=0, blocks_erased=0; int sector[LITTLEFS_CFG_PHYS_ERASE_SZ / LITTLEFS_CFG_SECTOR_SIZE]; + uint64_t tstart = mp_hal_ticks_ms(); + uint64_t tend = tstart; int res = lfs_fs_traverse(&littleFlash.lfs, _cb_traverse, (void *)lfs_blocks); @@ -998,21 +1002,34 @@ STATIC mp_obj_t vfs_littlefs_trim(size_t n_args, const mp_obj_t *args) } } } + tend = mp_hal_ticks_ms(); } else { - mp_printf(&mp_plat_print, "%sTrim ERROR (traverse)%s\r\n", term_color(RED), term_color(DEFAULT)); + if (do_print) mp_printf(&mp_plat_print, "%sTrim ERROR (traverse)%s\r\n", term_color(RED), term_color(DEFAULT)); return mp_const_none; } - mp_printf(&mp_plat_print, "%s LittleFS blocks: used=%u, free=%u (%d bytes/block)%s\r\n", term_color(CYAN), bused, bfree, LITTLEFS_CFG_SECTOR_SIZE, term_color(DEFAULT)); - mp_printf(&mp_plat_print, "%s Free flash sectors: %u; needs erase: %u%s\r\n", term_color(BROWN), sect_erase, sect_erased, term_color(DEFAULT)); - mp_printf(&mp_plat_print, "%s Free FS blocks: %u; needs erase: %u%s\r\n", term_color(BROWN), blocks_erase, blocks_erased, term_color(DEFAULT)); - if ((!do_erase) && ((sect_erased+blocks_erased) > 0)) { - mp_printf(&mp_plat_print, "%s Expected erase time: %.2f s%s\r\n", term_color(PURPLE), (double)(sect_erased + blocks_erased) * 0.075, term_color(DEFAULT)); + if (do_print) { + mp_printf(&mp_plat_print, "%s LittleFS blocks: used=%u, free=%u (%d bytes/block)%s\r\n", term_color(CYAN), bused, bfree, LITTLEFS_CFG_SECTOR_SIZE, term_color(DEFAULT)); + mp_printf(&mp_plat_print, "%s Free flash sectors: %u; needs erase: %u%s\r\n", term_color(BROWN), sect_erase, sect_erased, term_color(DEFAULT)); + mp_printf(&mp_plat_print, "%s Free FS blocks: %u; needs erase: %u%s\r\n", term_color(BROWN), blocks_erase, blocks_erased, term_color(DEFAULT)); + if ((!do_erase) && ((sect_erased+blocks_erased) > 0)) { + mp_printf(&mp_plat_print, "%s Expected erase time: %.2f s%s\r\n", term_color(PURPLE), (double)(sect_erased + blocks_erased) * 0.075, term_color(DEFAULT)); + } + else if ((sect_erased+blocks_erased) > 0) { + mp_printf(&mp_plat_print, "%s Erase time: %.2f s%s\r\n", term_color(PURPLE), (double)(tend - tstart) / 1000.0, term_color(DEFAULT)); + } } - - return mp_const_none; + mp_obj_t tuple[5]; + tuple[0] = mp_obj_new_int(sect_erase); + tuple[1] = mp_obj_new_int(sect_erased); + tuple[2] = mp_obj_new_int(blocks_erase); + tuple[3] = mp_obj_new_int(blocks_erased); + if ((!do_erase) && ((sect_erased+blocks_erased) > 0)) tuple[4] = mp_obj_new_int(0); + else tuple[4] = mp_obj_new_int(tend - tstart); + + return mp_obj_new_tuple(5, tuple); } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(littlefs_vfs_trim_obj, 0, 1, vfs_littlefs_trim); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(littlefs_vfs_trim_obj, 0, 2, vfs_littlefs_trim); //=============================================================== diff --git a/k210-freertos/platform/drivers/w25qxx.c b/k210-freertos/platform/drivers/w25qxx.c index 3666901..b706295 100644 --- a/k210-freertos/platform/drivers/w25qxx.c +++ b/k210-freertos/platform/drivers/w25qxx.c @@ -48,6 +48,8 @@ #include "FreeRTOS.h" #include "task.h" +#define CYCLES_PER_US (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000) + bool w25qxx_spi_check = false; bool w25qxx_debug = false; uintptr_t spi_adapter = 0; @@ -57,10 +59,6 @@ uint8_t work_trans_mode = 0; uint32_t w25qxx_max_speed = WQ25QXX_MAX_SPEED; uint32_t w25qxx_flash_speed = 0; uint32_t w25qxx_actual_speed = 0; -static uint32_t rd_count; -static uint32_t wr_count; -static uint32_t er_count; -static uint64_t op_time; // used only by 'w25qxx_write_data' uint8_t __attribute__((aligned(8))) swap_buf[w25qxx_FLASH_SECTOR_SIZE]; bool w25qxx_swap_dat = true; @@ -70,6 +68,11 @@ uint8_t *w25qxx_flash_ptr = (uint8_t *)SPI3_BASE_ADDR; uint16_t *w25qxx_flash_ptr16 = (uint16_t *)SPI3_BASE_ADDR; uint32_t *w25qxx_flash_ptr32 = (uint32_t *)SPI3_BASE_ADDR; +static uint32_t rd_count; +static uint32_t wr_count; +static uint32_t er_count; +static uint64_t op_time; + //-------------------------------------------------------------------------------------------------------------------- static enum w25qxx_status_t w25qxx_receive_data(uint8_t* cmd_buff, uint8_t cmd_len, uint8_t* rx_buff, uint32_t rx_len) { @@ -131,7 +134,7 @@ static enum w25qxx_status_t w25qxx_is_busy(void) //-------------------------------------------- static enum w25qxx_status_t w25qxx_wait_busy() { - uint64_t start_time = sys_ticks_us(); + uint64_t start_time = read_csr64(mcycle); uint64_t busy_time = 0; uint8_t status; @@ -139,10 +142,10 @@ static enum w25qxx_status_t w25qxx_wait_busy() w25qxx_read_status_reg1(&status); if ((status & REG1_BUSY_MASK) == 0) { // not busy - busy_time = sys_ticks_us() - start_time; - op_time += busy_time; - if (busy_time > 600000) { - LOGW("w25qxx_wait_busy", "BUSY for %lu us", op_time); + busy_time = read_csr64(mcycle) - start_time; + op_time += (busy_time / CYCLES_PER_US); + if (busy_time > (500000*CYCLES_PER_US)) { + LOGW("w25qxx_wait_busy", "BUSY for %lu us", busy_time / CYCLES_PER_US); } return W25QXX_OK; } @@ -260,8 +263,7 @@ static enum w25qxx_status_t w25qxx_read_data_less_64kb(uint32_t addr, uint8_t* d static enum w25qxx_status_t _w25qxx_read_data(uint32_t addr, uint8_t* data_buf, uint32_t length) { uint32_t len; - uint64_t ticks_start = sys_ticks_us(); - uint64_t ticks; + uint64_t ticks_start = read_csr64(mcycle); while (length) { len = length >= 0x010000 ? 0x010000 : length; w25qxx_read_data_less_64kb(addr, data_buf, len); @@ -269,9 +271,8 @@ static enum w25qxx_status_t _w25qxx_read_data(uint32_t addr, uint8_t* data_buf, data_buf += len; length -= len; } - ticks = sys_ticks_us(); rd_count++; - op_time += (ticks - ticks_start); + op_time += ((read_csr64(mcycle) - ticks_start) / CYCLES_PER_US); return W25QXX_OK; } @@ -460,6 +461,7 @@ uint32_t w25qxx_init(uintptr_t spi_in, uint8_t mode, double clock_rate) { configASSERT(mode < 3); work_trans_mode = mode; + uint8_t manuf_id, device_id; w25qxx_actual_speed = clock_rate; w25qxx_flash_speed = clock_rate; @@ -504,6 +506,7 @@ uint32_t w25qxx_init(uintptr_t spi_in, uint8_t mode, double clock_rate) spi_adapter = spi_stand; break; } + spi_dev_set_xip_mode(spi_adapter, false); return w25qxx_actual_speed; } diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/dmac.cpp b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/dmac.cpp index cdaa720..af29d14 100755 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/dmac.cpp +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/dmac.cpp @@ -241,8 +241,8 @@ class k_dma_driver : public dma_driver, public static_object, public exclusive_o if (!mem_type_src) { - if (src >= (void *)0x80600000) { - LOGW("[DMAC]", "SRC at %p used", alloc_mem); + if (alloc_mem >= (void *)0x80600000) { + LOGW("[DMAC]", "DEST at %p used", alloc_mem); } dma.sar = (uint64_t)src; dma.dar = (uint64_t)alloc_mem; @@ -403,13 +403,13 @@ class k_dma_driver : public dma_driver, public static_object, public exclusive_o #if FIX_CACHE //iomem_free(session_.alloc_mem); #else - free(session_.alloc_mem); + //free(session_.alloc_mem); #endif //session_.alloc_mem = NULL; if (count == 0) { - xSemaphoreGive(completion_event); + if (completion_event) xSemaphoreGive(completion_event); return; } @@ -417,7 +417,7 @@ class k_dma_driver : public dma_driver, public static_object, public exclusive_o dest_inc = !dest_inc; configASSERT(count > 0 && count <= 0x3fffff); configASSERT((dmac.chen & (1 << channel_)) == 0); - configASSERT(element_size >= 4); + configASSERT(element_size <= 16); configASSERT(src_num > 0 && src_num <= MAX_PING_PONG_SRCS); configASSERT(dest_num > 0 && dest_num <= MAX_PING_PONG_SRCS); @@ -556,13 +556,13 @@ class k_dma_driver : public dma_driver, public static_object, public exclusive_o // LoBo: do not assert, but provide the interrupt status in global variable // to be used by caller function dmac_intstatus = dma.intstatus; - if ((dmac_intstatus & 0x2) == 0) { - LOGW("[DMAC]", "ISR, wrong int status (%08lx)", dmac_intstatus); - } dma.intclear = 0xFFFFFFFF; if (driver.session_.is_loop) { + if ((dmac_intstatus & 0x02) == 0) { + atomic_set(driver.session_.stop_signal, 1); + } if (atomic_read(driver.session_.stop_signal)) { if (driver.session_.stage_completion_handler) @@ -585,12 +585,13 @@ class k_dma_driver : public dma_driver, public static_object, public exclusive_o if (driver.session_.stage_completion_handler) driver.session_.stage_completion_handler(driver.session_.stage_completion_handler_data); + // enable DMA again dmac.chen |= 0x101 << driver.channel_; } } else { - if (driver.session_.flow_control != DMAC_MEM2MEM_DMA && driver.session_.element_size < 4) + if ((driver.session_.flow_control != DMAC_MEM2MEM_DMA) && (driver.session_.element_size < 4)) { if (driver.session_.flow_control == DMAC_PRF2MEM_DMA) { @@ -651,6 +652,11 @@ class k_dma_driver : public dma_driver, public static_object, public exclusive_o static int is_memory(uintptr_t address) { + /* K210 memory regions for DMA: + * 0x80000000 - 0x805FFFFF cached SRAM + * 0x40000000 - 0x407FFFFF non-cached SRAM + * 0x50450040 AES plan text/cipher text input data + */ enum { mem_len = 6 * 1024 * 1024, diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/spi.cpp b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/spi.cpp index cf61016..91f74e1 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/spi.cpp +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/bsp/device/spi.cpp @@ -29,17 +29,33 @@ #include #include #include +#include "gpiohs.h" -extern uint64_t dmac_intstatus; +#define SPI_SLAVE_MUTEX_WAIT_TIME 20 -using namespace sys; +extern uint64_t dmac_intstatus; // transmission length (frames) bellow which DMA transfer is not used // used only by SPI master // during the non-DMA transfer interrupts are disabled ! -#define SPI_TRANSMISSION_THRESHOLD 0x100000UL //0x400UL // byte threshold above which a DMA transfer is used -#define SPI_DMA_BLOCK_TIME 1000UL // DMA transfer block time in ms -#define SPI_SLAVE_INFO "K210 v1.2" // !must be exactly 9 bytes! +// LoBo: make this global variable so it can be changed during runtime +uint32_t SPI_TRANSMISSION_THRESHOLD = 0x4000; // byte threshold above which a DMA transfer is used +uint32_t SPI_SLAVE_TRANS_THRESHOLD = 128; // byte threshold above which a SPI Slave DMA transfer is used + +using namespace sys; + +#define SPI_DMA_BLOCK_TIME 1000UL // DMA transfer block time in ms +#define SPI_SLAVE_INFO "K210 v01.03" // !must be exactly 11 bytes (+ending 0)! +#define CYCLES_PER_US (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000) +#define MAX_SLAVE_TRANSFER_SIZE 65536 +#define SLAVE_OUTPUT_ENABLE_BITS 10 +#define SLAVE_COMMAND_LENGTH 16 +#define SLAVE_READ_BUFFER_LENGTH (SLAVE_COMMAND_LENGTH+2) +#define SLAVE_COMMAND_STATUS_LENGTH 12 + + +// !!! SPI SLAVE HAS ONLY 8 32-BIT FIFO ENTRIES !!! +#define SLAVE_FIFO_SIZE 8 /* SPI Controller */ @@ -52,7 +68,6 @@ typedef enum { IDLE, COMMAND, - TRANSFER, DEINIT, } spi_slave_status_e; @@ -61,19 +76,25 @@ typedef struct _spi_slave_instance size_t data_bit_length; volatile spi_slave_status_e status; volatile spi_slave_command_t command; - volatile spi_slave_command_t last_command; - volatile uint8_t *databuff_ptr; + volatile void *databuff_ptr; uint32_t databuff_size; uint32_t databuff_ro_size; int32_t mosi; int32_t miso; + int32_t cs_io_num; + int32_t handshake; + uint32_t crc_speed; + bool in_transfer; // true while in slave ISR + uint8_t cmd_data[SLAVE_COMMAND_LENGTH]; + uint8_t read_data[SLAVE_READ_BUFFER_LENGTH]; + uint8_t cmd_status[SLAVE_COMMAND_STATUS_LENGTH]; uintptr_t dma; - SemaphoreHandle_t dma_event; - SemaphoreHandle_t slave_event; - TaskHandle_t slave_task_handle; - spi_slave_receive_callback_t callback; - spi_slave_csum_callback_t csum_callback; + SemaphoreHandle_t dma_event; + SemaphoreHandle_t slave_event; + TaskHandle_t slave_task_handle; + QueueHandle_t slave_queue; + QueueHandle_t slave_mutex; // used to protect access to spi slave buffer } spi_slave_instance_t; static fpioa_io_config_t FUNC_SPI_SLAVE_MISO = { @@ -95,6 +116,8 @@ static fpioa_io_config_t FUNC_SPI_SLAVE_MISO = { .pad_di = 0 }; +volatile gpiohs_t* const gpiohs = (volatile gpiohs_t*)GPIOHS_BASE_ADDR; + static const char *TAG = "[SPI_DRIVER]"; static const char *SLAVE_TAG = "[SPI_SLAVE_DRIVER]"; @@ -142,24 +165,31 @@ class k_spi_driver : public spi_driver, public static_object, public free_object //----------------- void slave_deinit() { + spi_.imr = 0x00; pic_set_irq_enable(IRQN_SPI_SLAVE_INTERRUPT, 0); atomic_set(&slave_instance_.status, DEINIT); int tmo = 5000; while (slave_instance_.slave_task_handle != NULL) { - xSemaphoreGive(slave_instance_.slave_event); + if ((tmo % 100) == 0) xSemaphoreGive(slave_instance_.slave_event); vTaskDelay(5); tmo -= 5; if (tmo == 0) { - LOGE(TAG, "Slave task not stopped"); + vTaskDelete(slave_instance_.slave_task_handle); + slave_instance_.slave_task_handle = NULL; + LOGW(SLAVE_TAG, "Slave task forced to stop"); break; } } spi_.dmacr = 0x00; + spi_.txftlr = 0; + spi_.rxftlr = 0; spi_.ssienr = 0x00; sysctl_clock_disable(SYSCTL_CLOCK_SPI2); + sysctl_reset(SYSCTL_RESET_SPI2); vSemaphoreDelete(slave_instance_.dma_event); vSemaphoreDelete(slave_instance_.slave_event); dma_close(slave_instance_.dma); + vSemaphoreDelete(slave_instance_.slave_mutex); } //--------------- @@ -168,58 +198,231 @@ class k_spi_driver : public spi_driver, public static_object, public free_object } - //----------------------------------------------------------------------------------------------- - void slave_config(size_t data_bit_length, uint8_t *data, uint32_t len, uint32_t ro_len, - spi_slave_receive_callback_t callback, spi_slave_csum_callback_t csum_callback, - int priority, int mosi, int miso) + //-------------------------------------------------------------------------------------------------------------------------------- + bool slave_config(void *data, uint32_t len, uint32_t ro_len, QueueHandle_t queue, int priority, int mosi, int miso, int handshake) { + slave_instance_.slave_mutex = xSemaphoreCreateMutex(); + if (slave_instance_.slave_mutex == NULL) { + return false; + } + slave_instance_.dma_event = xSemaphoreCreateBinary(); + if (slave_instance_.dma_event == NULL) { + vSemaphoreDelete(slave_instance_.slave_mutex); + return false; + } + slave_instance_.slave_event = xSemaphoreCreateBinary(); + if (slave_instance_.slave_event == NULL) { + vSemaphoreDelete(slave_instance_.slave_mutex); + vSemaphoreDelete(slave_instance_.dma_event); + return false; + } + slave_instance_.cs_io_num = fpioa_get_io_by_function(FUNC_SPI_SLAVE_SS); + if (slave_instance_.cs_io_num < 0) { + vSemaphoreDelete(slave_instance_.slave_mutex); + vSemaphoreDelete(slave_instance_.dma_event); + vSemaphoreDelete(slave_instance_.slave_event); + return false; + } slave_instance_.status = IDLE; slave_instance_.databuff_ptr = data; slave_instance_.databuff_size = len; slave_instance_.databuff_ro_size = ro_len; - slave_instance_.data_bit_length = data_bit_length; + slave_instance_.data_bit_length = 8; slave_instance_.dma = dma_open_free(); - slave_instance_.dma_event = xSemaphoreCreateBinary(); - slave_instance_.slave_event = xSemaphoreCreateBinary(); - slave_instance_.csum_callback = csum_callback; - slave_instance_.callback = callback; + slave_instance_.slave_queue = queue; slave_instance_.mosi = mosi; slave_instance_.miso = miso; - uint8_t slv_oe = 10; + slave_instance_.handshake = handshake; + slave_instance_.in_transfer = false; + memset(slave_instance_.cmd_data, 0, SLAVE_COMMAND_LENGTH); + slave_set_read_buffer(slave_instance_.cmd_data); + uint16_t size = (len > 1000) ? 1000 : len; + uint64_t tend, tstart = read_csr64(mcycle); + uint32_t crc_test = hal_crc16((const void*)(slave_instance_.databuff_ptr), size, 0); + tend = read_csr64(mcycle); + crc_test = (((tend - tstart) * 1000) / CYCLES_PER_US) * (1000 / size); + slave_instance_.crc_speed = crc_test; + sysctl_reset(SYSCTL_RESET_SPI2); sysctl_clock_enable(SYSCTL_CLOCK_SPI2); sysctl_clock_set_threshold(SYSCTL_THRESHOLD_SPI2, 4); - LOGV(SLAVE_TAG, "SPI Clk: %u", sysctl_clock_get_freq(SYSCTL_CLOCK_SPI2)); - - uint32_t data_width = data_bit_length / 8; - - spi_.ssienr = 0x00; - spi_.ctrlr0 = (0x0 << mod_off_) | (0x1 << slv_oe) | ((data_bit_length - 1) << dfs_off_); - spi_.dmatdlr = 0x04; - spi_.dmardlr = 0x03; - spi_.dmacr = 0x00; - spi_.txftlr = 0x00; - spi_.rxftlr = 0x08 / data_width - 1; - + LOGV(SLAVE_TAG, "Clock = %u", sysctl_clock_get_freq(SYSCTL_CLOCK_SPI2)); + + spi_.ssienr = 0x00; // disable spi + /* Setup SPI: + * SPI_FRF (SpiFrame Format) = Standard + * DFS_32 (Data Frame Size in 32bitmode) = 7 (8-bit mode) + * CFS (Control Frame size) = 0 + * SRL (Shift register loop) = 0 + * SLV_OE (Slave Output Enable) = 1 (disabled) + * TMOD (Transfer Mode) = 0 (Transmit&receive) + * SCPOL (Serial Clock Polarity) = 0 (Inactive state is low) + * SCPH (Serial Clock Phase) = 0 (Clock toggles in middle of first bit) + * FRF (Frame Format) = 0 (Motorola SPI Frame Format) + * DFS (Data Frame Size) = 0 + */ + spi_.ctrlr0 = (0x0 << mod_off_) | (0x1 << SLAVE_OUTPUT_ENABLE_BITS) | (7 << dfs_off_); + spi_.dmatdlr = 0x01; // DMA Transmit Data Level = 1 + spi_.dmardlr = 0x00; // DMA Receive Data Level = 0+1 + spi_.dmacr = 0x00; // DMA Control Register = 0 (DMA disabled) + spi_.txftlr = 0; // Transmit FIFO Threshold Level = 0 + spi_.rxftlr = 0; // Receive FIFO Threshold level = 0 (Interrupt on 1 byte received) + + // Configure interrupt controller for SPI interrupts pic_set_irq_priority(IRQN_SPI_SLAVE_INTERRUPT, 4); pic_set_irq_enable(IRQN_SPI_SLAVE_INTERRUPT, 1); pic_set_irq_handler(IRQN_SPI_SLAVE_INTERRUPT, spi_slave_irq, this); + // Create SPI Slave task slave_instance_.slave_task_handle = NULL; - auto ret = xTaskCreate(spi_slave_irq_thread, "spi_slave_irq", configMINIMAL_STACK_SIZE, this, priority+2, &slave_instance_.slave_task_handle); - configASSERT(ret == pdTRUE); - spi_.imr = 0x10; - spi_.ssienr = 0x01; + auto ret = xTaskCreate(spi_slave_process_task, "SPI Slave Task", configMINIMAL_STACK_SIZE, this, priority+2, &slave_instance_.slave_task_handle); + if (ret != pdTRUE) { + vSemaphoreDelete(slave_instance_.slave_mutex); + vSemaphoreDelete(slave_instance_.dma_event); + vSemaphoreDelete(slave_instance_.slave_event); + return false; + } + + spi_.imr = 0x10; // spi interrupt enable + spi_.ssienr = 0x01; // spi enable + + set_handshake(slave_instance_.handshake, GPIO_PV_HIGH); + return true; + } + + // Set the handshake line (if used) to requested level + // or pulse it low for requested time in us + //-------------------------------------- + bool slave_set_handshake(uint16_t value) + { + bool ret = false; + bool in_transfer = atomic_read(&slave_instance_.in_transfer); + if ((!in_transfer) && (slave_instance_.handshake >= 0)) { + if (value < 2) set_handshake(slave_instance_.handshake, value); + else { + if(value > 500) value = 500; + uint64_t tend = read_csr64(mcycle) + (value * CYCLES_PER_US); + uint64_t tcurrent = tend; + set_handshake(slave_instance_.handshake, GPIO_PV_LOW); + while (tcurrent <= tend) { + tcurrent = read_csr64(mcycle); + } + set_handshake(slave_instance_.handshake, GPIO_PV_HIGH); + ret = true; + } + } + return ret; + } + + //------------------------------------------------------------------ + bool slave_set_buffer(uint8_t *buffer, uint32_t addr, uint32_t size) + { + if (xSemaphoreTake(slave_instance_.slave_mutex, 10) != pdTRUE) return false; + memcpy((uint8_t *)slave_instance_.databuff_ptr+addr, buffer, size); + xSemaphoreGive(slave_instance_.slave_mutex); + return true; + } + + //----------------------------------------- + bool slave_set_read_buffer(uint8_t *buffer) + { + if (atomic_read(&slave_instance_.in_transfer)) return false; + spi_.imr = 0x00; // Disable SPI interrupt + + if (buffer) memcpy(slave_instance_.read_data, buffer, SLAVE_COMMAND_LENGTH); + else memcpy(slave_instance_.read_data, (uint8_t *)slave_instance_.databuff_ptr, SLAVE_COMMAND_LENGTH); + + uint16_t crc = hal_crc16((const void*)(slave_instance_.read_data), SLAVE_COMMAND_LENGTH, 0); + slave_instance_.read_data[SLAVE_READ_BUFFER_LENGTH-2] = crc & 0xff; + slave_instance_.read_data[SLAVE_READ_BUFFER_LENGTH-1] = crc >> 8; + spi_.imr = 0x10; // Enable SPI interrupt + return true; + } + + //--------------------------------------------------------------------- + bool slave_fill_buffer(uint8_t fill_byte, uint32_t addr, uint32_t size) + { + if (xSemaphoreTake(slave_instance_.slave_mutex, 10) != pdTRUE) return false; + memset((uint8_t *)slave_instance_.databuff_ptr+addr, fill_byte, size); + xSemaphoreGive(slave_instance_.slave_mutex); + return true; + } + + //------------------------------------------------------------------ + bool slave_get_buffer(uint8_t *buffer, uint32_t addr, uint32_t size) + { + if (xSemaphoreTake(slave_instance_.slave_mutex, 10) != pdTRUE) return false; + memcpy(buffer, (uint8_t *)slave_instance_.databuff_ptr+addr, size); + xSemaphoreGive(slave_instance_.slave_mutex); + return true; } private: - //--------------------------------------------- - void setup_device(k_spi_device_driver &device); - // SPI Slave command processing task - // Runs with the priority higher than the main task - //---------------------------------------------- - static void spi_slave_irq_thread(void *userdata) + //-------------------------------------------------------------------------- + static bool wait_cs(int32_t cs_io_num, uint32_t tmo, gpio_pin_value_t level) + { + bool res = false; + uint64_t time_end = read_csr64(mcycle) + (tmo * CYCLES_PER_US); + // wait for CS level + while (read_csr64(mcycle) < time_end) { + if (fpioa_get_pad_di(cs_io_num) == level) { + res = true; + break; + } + } + return res; + } + + //------------------------------ + static void wait_us(uint16_t us) + { + uint64_t time_end = read_csr64(mcycle) + (us * CYCLES_PER_US); + while (read_csr64(mcycle) < time_end) { + ; + } + } + + // ------------------------------------------------------------------------------------ + // SPI SLAVE uses only one pin (mosi) for both receive and transfer (FUNC_SPI_SLAVE_D0) + // If 'miso' pin is defined, we are switching SPI slave pin to it when sending data + //-------------------------------------------- + static void switch_to_miso(int mosi, int miso) + { + if (miso >= 0) { + // disconnect 'mosi' pin and + // setup 'miso' pin for FUNC_SPI_SLAVE_D0 + fpioa_set_function(mosi, FUNC_RESV0); + fpioa_set_io(miso, &FUNC_SPI_SLAVE_MISO); + } + } + + //-------------------------------------------- + static void switch_to_mosi(int mosi, int miso) + { + if (miso >= 0) { + // disconnect 'miso' pin and + // setup 'mosi' for FUNC_SPI_SLAVE_D0 again + fpioa_set_function(miso, FUNC_RESV0); + fpioa_set_function(mosi, FUNC_SPI_SLAVE_D0); + } + } + + //----------------------------------------------- + static void set_handshake(int32_t pin, int value) + { + if (pin >= 0) { + uint32_t org = (*gpiohs->output_val.u32) & ~(1 << pin); + *gpiohs->output_val.u32 = org | (value & (1 << pin)); + } + } + + /* ===== SPI Slave command processing task ===== + * Runs with the priority higher than the main task + * + */ + //------------------------------------------------ + static void spi_slave_process_task(void *userdata) { auto &driver = *reinterpret_cast(userdata); while (1) @@ -229,10 +432,17 @@ class k_spi_driver : public spi_driver, public static_object, public free_object // slave interrupt occurred spi_slave_status_e status = atomic_read(&driver.slave_instance_.status); if (status == IDLE) { + // Full command block received atomic_cas((volatile int *)&driver.slave_instance_.status, IDLE, COMMAND); spi_slave_command_mode(userdata); + atomic_set(&driver.slave_instance_.in_transfer, false); } else if (status == DEINIT) { + auto &command = driver.command(); + memset((void *)&driver.slave_instance_.command, 0, sizeof(spi_slave_command_t)); + command.err = SPI_CMD_ERR_EXIT; + if (driver.slave_instance_.slave_queue != NULL) + xQueueSend(driver.slave_instance_.slave_queue, (void *)&command, 0); break; } } @@ -241,402 +451,741 @@ class k_spi_driver : public spi_driver, public static_object, public free_object vTaskDelete(NULL); } - // SPI Slave ISR + /* ========= SPI Slave ISR ========= + * Executed during the Idle phase whenever SPI slave receives a new byte + * 16 bytes command block is then received + */ //---------------------------------- static void spi_slave_irq(void *ctx) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; + uint64_t time_start = read_csr64(mcycle); auto &driver = *reinterpret_cast(ctx); auto &spi_handle = driver.spi(); - spi_handle.imr = 0x00; - *reinterpret_cast(spi_handle.icr); - // inform the slave task about the event - xSemaphoreGiveFromISR(driver.slave_instance_.slave_event, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR(); + *reinterpret_cast(spi_handle.icr); // clear interrupt + + spi_slave_status_e status = atomic_read(&driver.slave_instance_.status); + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + uint32_t i; + uint32_t size = SLAVE_COMMAND_LENGTH; + uint32_t fifo_len, to_read; + uint8_t *buf = driver.slave_instance_.cmd_data; + bool is_ok = true; + + atomic_set(&driver.slave_instance_.in_transfer, true); + int mask = taskENTER_CRITICAL_FROM_ISR(); + spi_handle.imr = 0x00; // disable SPI interrupts + + // save the 1st byte + //while (spi_handle.rxflr == 0) { + // ; + //} + *buf = (uint8_t)spi_handle.dr[0]; + if ((*buf == SPI_CMD_READ_TRANS) || (*buf == SPI_CMD_STATUS_TRANS)) { + // --- Master read transaction --- + uint8_t *tbuf = driver.slave_instance_.read_data; + size = SLAVE_READ_BUFFER_LENGTH; + if (*buf == SPI_CMD_STATUS_TRANS) { + tbuf = driver.slave_instance_.cmd_status; + size = SLAVE_COMMAND_STATUS_LENGTH; + } + uint32_t idx = 0; + uint32_t to_send; + // wait for transaction to finish + if (wait_cs(driver.slave_instance_.cs_io_num, 50, GPIO_PV_HIGH)) { + spi_handle.ssienr = 0x00; // spi disable + // set output mode + switch_to_miso(driver.slave_instance_.mosi, driver.slave_instance_.miso); + set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 1 << driver.tmod_off_); // Set Transmit only mode + set_bit_mask(&spi_handle.ctrlr0, 1 << SLAVE_OUTPUT_ENABLE_BITS, 0 << SLAVE_OUTPUT_ENABLE_BITS); // Enable SPI Slave output + spi_handle.ssienr = 0x01; // spi enable + while (size) { + to_send = SLAVE_FIFO_SIZE - spi_handle.txflr; + if (size < to_send) to_send = size; + for (int i=0; i size) ? size : fifo_len; + for (i=0; i 0) && (fpioa_get_pad_di(driver.slave_instance_.cs_io_num))) { + // timeout + is_ok = false; + break; + } + } + + if ((is_ok) && (status == IDLE)) { + // save the command block start time + // the actual transaction start time is 1 byte transfer time less than this + driver.slave_instance_.command.command_time = read_csr64(mcycle); + spi_handle.ssienr = 0x00; // spi disable + taskEXIT_CRITICAL_FROM_ISR(mask); + // Command block received, inform the SPI Slave task + driver.slave_instance_.command.start_time = time_start-500; + xSemaphoreGiveFromISR(driver.slave_instance_.slave_event, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR(); + } + else { + taskEXIT_CRITICAL_FROM_ISR(mask); + // error receiving command block, re-enable spi interrupt + atomic_set(&driver.slave_instance_.in_transfer, false); + spi_handle.imr = 0x10; + } + } } - // Setup the slave idle mode, wait for 8-byte command - //---------------------------------------------------------- - static void spi_slave_idle_mode(void *userdata, bool irq_en) + // Wait for DMA transfer initiated from command handler to finish + //----------------------------------------------------------------------------- + static void _wait_slave_transfer_finish(void *userdata, volatile uint32_t fifo) + { + auto &driver = *reinterpret_cast(userdata); + + if (xSemaphoreTake(driver.slave_instance_.dma_event, 100 / portTICK_PERIOD_MS) != pdTRUE) { + driver.slave_instance_.command.end_time = read_csr64(mcycle); + driver.slave_instance_.command.err = SPI_CMD_ERR_TIMEOUT; + LOGD(SLAVE_TAG, "DMAC error status=0x%08lX", dmac_intstatus); + } + else { + // wait until transfer finished (CS = high) + if (!wait_cs(driver.slave_instance_.cs_io_num, 100, GPIO_PV_HIGH)) { + driver.slave_instance_.command.err = SPI_CMD_ERR_TIMEOUT; + } + driver.slave_instance_.command.end_time = read_csr64(mcycle); + } + } + + /* + // This is executed from DMAC when the transfer has ended + //-------------------------------------------------- + static void slave_completion_handler(void *userdata) + { + auto &driver = *reinterpret_cast(userdata); + dma_stop(driver.slave_instance_.dma); + } + */ + + //-------------------------------------------------------------------------------------- + static uint32_t *alloc_buffer(uint32_t size, void *src_buf, uint16_t crc, uint8_t dummy) + { + uint32_t sz = (size & 0xfffffffc) + dummy + 8; + uint32_t *buf = (uint32_t *)pvPortMalloc(sz * sizeof(uint32_t)); + + if (buf) { + if (src_buf) { + for (int i=0; i> 8) & 0xFF); + } + if ((buf+sz) > (uint32_t *)0x80600000) buf -= 0x40000000; + } + return buf; + } + + //-------------------------------------- + static void prepare_send(void *userdata) { - uint8_t slv_oe = 10; auto &driver = *reinterpret_cast(userdata); auto &spi_handle = driver.spi(); - uint32_t data_width = driver.slave_instance_.data_bit_length / 8; - driver.slave_instance_.status = IDLE; - spi_handle.ssienr = 0x00; - spi_handle.ctrlr0 = (0x0 << driver.mod_off_) | (0x1 << slv_oe) | ((driver.slave_instance_.data_bit_length - 1) << driver.dfs_off_); - spi_handle.rxftlr = 0x08 / data_width - 1; // expecting 8-byte command - spi_handle.dmacr = 0x00; - spi_handle.imr = 0x10; - if (irq_en) spi_handle.ssienr = 0x01; + switch_to_miso(driver.slave_instance_.mosi, driver.slave_instance_.miso); + + //spi_handle.ctrlr0 = (0x0 << driver.mod_off_) | (0x0 << SLAVE_OUTPUT_ENABLE_BITS) | (7 << driver.dfs_off_); + set_bit_mask(&spi_handle.ctrlr0, 1 << SLAVE_OUTPUT_ENABLE_BITS, 0 << SLAVE_OUTPUT_ENABLE_BITS); // Enable SPI Slave output + set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 1 << driver.tmod_off_); // Set Transmit only mode + spi_handle.dmacr = 0x02; // Transmit DMA Enable + spi_handle.imr = 0x00; // Disable SPI interrupts + spi_handle.ssienr = 0x01; // SPI enable - LOGV(SLAVE_TAG, "In IDLE mode"); + dma_set_request_source(driver.slave_instance_.dma, driver.dma_req_ + 1); + + driver.slave_instance_.command.transfer_time = read_csr64(mcycle); } - // Wait for DMA transfer initiated from command handler to finish - //----------------------------------------------- - static bool _wait_transfer_finish(void *userdata) + //-------------------------------------------------------------------------- + static void receive_no_dma(void *userdata, uint8_t *buffer, uint32_t length) { auto &driver = *reinterpret_cast(userdata); - //auto &spi_handle = driver.spi(); - - // timeout in ms - uint64_t tstart = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - uint64_t tend = tstart; - bool f = true; - int tmo = 200; - while (1) { - if (xSemaphoreTake(driver.slave_instance_.dma_event, 2 / portTICK_PERIOD_MS) == pdTRUE) break; - tmo -= 2; - if (tmo < 0) { - f = false; - dma_stop(driver.slave_instance_.dma); - if (xSemaphoreTake(driver.slave_instance_.dma_event, 500 / portTICK_PERIOD_MS) == pdTRUE) { - driver.slave_instance_.command.err = SPI_CMD_ERR_ERROR; - LOGW(SLAVE_TAG, "DMA transfer not finished, DMA stopped"); + auto &spi_handle = driver.spi(); + + vTaskEnterCritical(); + + // prepare receive + set_bit_mask(&spi_handle.ctrlr0, 1 << SLAVE_OUTPUT_ENABLE_BITS, 1 << SLAVE_OUTPUT_ENABLE_BITS); // Disable SPI Slave output + set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 2 << driver.tmod_off_); // Set Receive only mode + spi_handle.dmacr = 0x00; // Receive DMA Disable + spi_handle.imr = 0x00; // Disable SPI interrupts + spi_handle.ssienr = 0x01; // SPI enable + + driver.slave_instance_.command.transfer_time = read_csr64(mcycle); + set_handshake(driver.slave_instance_.handshake, GPIO_PV_LOW); + + uint32_t size = length; + uint32_t idx = 0; + uint32_t to_receive; + if (wait_cs(driver.slave_instance_.cs_io_num, 200, GPIO_PV_LOW)) { + while (size) { + to_receive = spi_handle.rxflr; + if (size < to_receive) to_receive = size; + for (int i=0; i= 0) { - // Set 'miso' for FUNC_SPI_SLAVE_D0 - fpioa_set_function(mosi, FUNC_RESV0); - fpioa_set_io(miso, &FUNC_SPI_SLAVE_MISO); + auto &driver = *reinterpret_cast(userdata); + auto &command = driver.command(); + + // confirm receiving data by sending the status 9-byte block + // 1st 6 bytes of the received command block + status + crc16 + for (int i=0; i> 8; } - //-------------------------------------------- - static void switch_to_mosi(int mosi, int miso) + //----------------------------------------------------------------------- + static void send_no_dma(void *userdata, uint8_t *buffer, uint32_t length) { - if (miso >= 0) { - // Set 'mosi' for FUNC_SPI_SLAVE_D0 - // wait 10 us, allow all data to be transfered - uint64_t time_us = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - uint64_t time_end = time_us + 8; - while (time_us < time_end) { - time_us = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); + auto &driver = *reinterpret_cast(userdata); + auto &spi_handle = driver.spi(); + auto &command = driver.command(); + + uint8_t *buf = buffer; + uint32_t size = length; + if (buffer == NULL) { + // confirm receiving data by sending the status 9-byte block + // 1st 6 bytes of the received command block + status + crc16 + uint8_t sbuf[9+command.dummy_bytes]; + set_confirm_data(userdata, sbuf); + buf = sbuf; + size = 9 + command.dummy_bytes; + } + + if (driver.slave_instance_.miso < 0) wait_us(20); + vTaskEnterCritical(); + switch_to_miso(driver.slave_instance_.mosi, driver.slave_instance_.miso); + + // Switch to spi slave output mode + set_bit_mask(&spi_handle.ctrlr0, 1 << SLAVE_OUTPUT_ENABLE_BITS, 0 << SLAVE_OUTPUT_ENABLE_BITS); // Enable SPI Slave output + set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 1 << driver.tmod_off_); // Set Transmit only mode + spi_handle.dmacr = 0x00; // Transmit DMA Disable + spi_handle.imr = 0x00; // Disable SPI interrupts + spi_handle.ssienr = 0x01; // SPI enable + + uint32_t idx = 0; + uint32_t fifo_len = SLAVE_FIFO_SIZE - spi_handle.txflr; + uint32_t to_send = (fifo_len > size) ? size : fifo_len ; + for (int i=0; i size) ? size : fifo_len ; + for (int i=0; i(userdata); auto &spi_handle = driver.spi(); - uint64_t time_us, end_time_us; - uint8_t cmd_data[8], sum = 0; - uint8_t slv_oe = 10; - memset((void *)&driver.slave_instance_.command, 0, sizeof(spi_slave_command_t)); - driver.slave_instance_.command.time = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); + auto &command = driver.command(); - uint32_t data_width = (driver.slave_instance_.data_bit_length + 7) / 8; - - // === Read the 8-byte command structure === - vTaskEnterCritical(); - switch (data_width) - { - case 4: - for (uint32_t i = 0; i < 8 / 4; i++) - ((uint32_t *)cmd_data)[i] = spi_handle.dr[0]; - break; - case 2: - for (uint32_t i = 0; i < 8 / 2; i++) - ((uint16_t *)cmd_data)[i] = spi_handle.dr[0]; - break; - default: - for (uint32_t i = 0; i < 8; i++) - cmd_data[i] = spi_handle.dr[0]; - break; + uint64_t time_us = driver.slave_instance_.command.start_time; + uint64_t time_end = driver.slave_instance_.command.command_time; + memset((void *)&driver.slave_instance_.command, 0, sizeof(spi_slave_command_t)); + if ((driver.slave_instance_.cmd_data[0] == SPI_CMD_READ_TRANS) || (driver.slave_instance_.cmd_data[0] == SPI_CMD_STATUS_TRANS)) { + // special case, processed in ISR + command.cmd = driver.slave_instance_.cmd_data[0]; + // Send the status (transaction result) to the main task + if (driver.slave_instance_.slave_queue != NULL) + xQueueSend(driver.slave_instance_.slave_queue, (void *)&command, 0); + atomic_set(&driver.slave_instance_.status, IDLE); + return; } - vTaskExitCritical(); - time_us = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - end_time_us = time_us; - // calculate csum - for (uint32_t i = 0; i < 7; i++) { - sum ^= cmd_data[i]; + driver.slave_instance_.command.start_time = time_us; + driver.slave_instance_.command.command_time = time_end; + + uint16_t cmd_crc = 0xFFFF; + uint16_t rcv_crc; + int stop_signal = 0; + const volatile void *srcs[1]; + volatile void *dests[1]; + volatile uint8_t spi_slave_dummy_bytes[8]; + uint32_t *tmp_buffer = NULL; + uint32_t data_length = 0; + bool with_crc = false; + bool wr_confirm = false; + + memset((void *)spi_slave_dummy_bytes, 0xFF, 8); + // set the command start time + command.transfer_time = command.start_time; + command.end_time = 0; + command.crc16 = 0xFFFF; + + // Check command crc + cmd_crc = hal_crc16((const void*)driver.slave_instance_.cmd_data, 14, 0); + rcv_crc = driver.slave_instance_.cmd_data[14] | (driver.slave_instance_.cmd_data[15] << 8); + if ( rcv_crc != cmd_crc) { + command.err = SPI_CMD_ERR_CSUM; + goto exit; } - driver.slave_instance_.command.cmd = cmd_data[0]; - driver.slave_instance_.command.addr = cmd_data[1] | (cmd_data[2] << 8) | (cmd_data[3] << 16); - driver.slave_instance_.command.len = cmd_data[4] | (cmd_data[5] << 8) | (cmd_data[6] << 16); + command.cmd = driver.slave_instance_.cmd_data[0] & 0x0F; + if ((command.cmd == SPI_CMD_WRSTAT) || (command.cmd == SPI_CMD_WRSTAT_CONFIRM)) { + command.opt = driver.slave_instance_.cmd_data[1] & 0x0F; + command.dummy_bytes = driver.slave_instance_.cmd_data[1] >> 4; + memcpy((void *)command.user_data, driver.slave_instance_.cmd_data+2, 12); + } + else { + command.opt = (driver.slave_instance_.cmd_data[0] >> 4); + command.addr = driver.slave_instance_.cmd_data[1] | (driver.slave_instance_.cmd_data[2] << 8) | ((driver.slave_instance_.cmd_data[3] & 0x0F) << 16); + command.len = (driver.slave_instance_.cmd_data[4] | (driver.slave_instance_.cmd_data[5] << 8)) + 1; + command.dummy_bytes = driver.slave_instance_.cmd_data[3] >> 4; + with_crc = (command.opt & 0x01); + wr_confirm = (command.opt & 0x02); + } + data_length = command.len + command.dummy_bytes; - if (cmd_data[7] != sum) { - driver.slave_instance_.command.err = SPI_CMD_ERR_CSUM; + if ((command.len > driver.slave_instance_.databuff_size) || (command.len > MAX_SLAVE_TRANSFER_SIZE)) { + command.err = SPI_CMD_ERR_LENGTH; goto exit; } - if ((driver.slave_instance_.command.len > driver.slave_instance_.databuff_size) || (driver.slave_instance_.command.len == 0)) { - driver.slave_instance_.command.err = SPI_CMD_ERR_LENGTH; - goto exit; + + // === Command ok, process it ================================================================= + //xSemaphoreTake(driver.slave_instance_.dma_event, 0); // ignore any received events + stop_signal = 1; // finish DMA transfer after all bytes transfered + command.err = SPI_CMD_ERR_OK; + + //----------------------------------------------------------------------------- + if ((command.cmd == SPI_CMD_WRSTAT) || (command.cmd == SPI_CMD_WRSTAT_CONFIRM)) + { + if (command.cmd == SPI_CMD_WRSTAT_CONFIRM) { + send_no_dma(userdata, NULL, 0); + } } + //------------------------------------- + else if (command.cmd == SPI_CMD_RDSTAT) + { + // ---------------------------------------------- + // Send 1st 4 bytes from SPI Slave buffer + crc16 + // ---------------------------------------------- + + if ((command.len != 4) || (!with_crc)) { + command.err = SPI_CMD_ERR_LENGTH; + goto dummysend; + } + uint8_t buf[6+command.dummy_bytes]; - // === Command ok, process it === - spi_handle.ssienr = 0x00; - //------------------------------------------------------------------------------------------------------------------------------------------ - if ((driver.slave_instance_.command.cmd == SPI_CMD_READ_DATA_BLOCK) || (driver.slave_instance_.command.cmd == SPI_CMD_READ_DATA_BLOCK_CSUM)) + xSemaphoreTake(driver.slave_instance_.slave_mutex, 2); + memcpy(buf+command.dummy_bytes, (uint8_t *)driver.slave_instance_.databuff_ptr, 4); + xSemaphoreGive(driver.slave_instance_.slave_mutex); + + command.crc16 = hal_crc16((const void*)(buf+command.dummy_bytes), 4, 0); + buf[4+command.dummy_bytes] = command.crc16 & 0xff; + buf[5+command.dummy_bytes] = command.crc16 >> 8; + + send_no_dma(userdata, buf, 6+command.dummy_bytes); + } + //------------------------------------------------ + else if ((command.cmd == SPI_CMD_READ_DATA_BLOCK)) { - // --------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------- // Send requested number of bytes from requested slave buffer address - // In case of READ_DATA_BLOCK_CSUM command, append 2-bytes checksum to the sent data - // --------------------------------------------------------------------------------- - - uint8_t csum_bkp[2] = {0}; - uint32_t data_len = driver.slave_instance_.command.len; - // check if the requested data fits into slave buffer - if (driver.slave_instance_.command.addr >= driver.slave_instance_.databuff_size) { - driver.slave_instance_.command.err = SPI_CMD_ERR_ADDRESS; - goto exit; + // If the crc is requested, append 2-bytes checksum to the sent data + // 2-bytes CRC16 in case of SPI_CMD_READ_DATA_BLOCK_CSUM is NOT INCLUDED in requested length + // ----------------------------------------------------------------------------------------- + + // check if the requested data are inside the slave buffer + if (command.addr >= driver.slave_instance_.databuff_size) { + command.err = SPI_CMD_ERR_ADDRESS; + goto dummysend; } - if ((driver.slave_instance_.command.addr + data_len) > driver.slave_instance_.databuff_size) { - data_len = driver.slave_instance_.databuff_size - driver.slave_instance_.command.addr; + if ((command.addr + command.len) > driver.slave_instance_.databuff_size) { + command.err = SPI_CMD_ERR_LENGTH; + goto dummysend; } - - if (driver.slave_instance_.command.cmd == SPI_CMD_READ_DATA_BLOCK_CSUM) { + xSemaphoreTake(driver.slave_instance_.slave_mutex, 2); + if (with_crc) { // 2-byte checksum will be appended to the data - uint16_t csum = 0; - if (driver.slave_instance_.csum_callback) { - csum = driver.slave_instance_.csum_callback((const uint8_t *)(driver.slave_instance_.databuff_ptr+driver.slave_instance_.command.addr), data_len); - } - csum_bkp[0] = *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len); - csum_bkp[1] = *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len + 1); - *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len) = csum & 0xff; - *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len + 1) = (csum >> 8) & 0xff; - data_len += 2; + command.crc16 = hal_crc16((const void*)((uint8_t *)driver.slave_instance_.databuff_ptr + command.addr), command.len, 0); + data_length += 2; } - driver.slave_instance_.command.err = SPI_CMD_ERR_OK; - size_t tx_frames = (data_len / data_width); // + 8; - spi_handle.ctrlr0 = (0x0 << driver.mod_off_) | (0x0 << slv_oe) | ((driver.slave_instance_.data_bit_length - 1) << driver.dfs_off_); - set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 1 << driver.tmod_off_); - spi_handle.dmacr = 0x02; - spi_handle.imr = 0x00; - spi_handle.ssienr = 0x01; - switch_to_miso(driver.slave_instance_.mosi, driver.slave_instance_.miso); + if (command.len > SPI_SLAVE_TRANS_THRESHOLD) { + // allocate temporary buffer for transfer and copy data from slave buffer into it + tmp_buffer = alloc_buffer(command.len, (void *)((uint8_t *)driver.slave_instance_.databuff_ptr+command.addr), command.crc16, command.dummy_bytes); + xSemaphoreGive(driver.slave_instance_.slave_mutex); + if (tmp_buffer == NULL) { + command.err = SPI_CMD_ERR_MEMORY; + goto dummysend; + } + + srcs[0] = (void *)tmp_buffer; + dests[0] = (void *)&spi_handle.dr[0]; + + prepare_send(userdata); - end_time_us = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - dma_set_request_source(driver.slave_instance_.dma, driver.dma_req_ + 1); - dma_transmit_async(driver.slave_instance_.dma, (void *)(driver.slave_instance_.databuff_ptr+driver.slave_instance_.command.addr), &spi_handle.dr[0], 1, 0, data_width, tx_frames, 1, driver.slave_instance_.dma_event); + dma_loop_async(driver.slave_instance_.dma, srcs, 1, dests, 1, true, false, 4, data_length, 1, + NULL, userdata, driver.slave_instance_.dma_event, &stop_signal); + set_handshake(driver.slave_instance_.handshake, GPIO_PV_LOW); - _wait_transfer_finish(userdata); + _wait_slave_transfer_finish(userdata, spi_handle.txflr); - switch_to_mosi(driver.slave_instance_.mosi, driver.slave_instance_.miso); + switch_to_mosi(driver.slave_instance_.mosi, driver.slave_instance_.miso); + } + else { + // short blocks are sent without using DMA + uint8_t buf[data_length]; + for (int i=0; i> 8; - if (driver.slave_instance_.command.cmd == SPI_CMD_READ_DATA_BLOCK_CSUM) { - // restore data buffer - data_len -= 2; - *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len) = csum_bkp[0]; - *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len + 1) = csum_bkp[1]; + send_no_dma(userdata, buf, data_length); } } //------------------------------------------------------------------------------------------------------------------------------------------------- - else if ((driver.slave_instance_.command.cmd == SPI_CMD_WRITE_DATA_BLOCK) || (driver.slave_instance_.command.cmd == SPI_CMD_WRITE_DATA_BLOCK_CSUM)) + else if (command.cmd == SPI_CMD_WRITE_DATA_BLOCK) { - // --------------------------------------------------------------------- + // ------------------------------------------------------------------------------------------ // Receive requested number of bytes into requested slave buffer address - // --------------------------------------------------------------------- + // 2-bytes CRC16 in case of SPI_CMD_WRITE_DATA_BLOCK_CSUM is NOT INCLUDED in requested length + // if CRC is provided, received data is checked for crc match before saving to spi buffer + // ------------------------------------------------------------------------------------------ - uint8_t csum_bkp[2] = {0}; - int data_len = driver.slave_instance_.command.len; + if (with_crc) data_length += 2; + else data_length = command.len; // check if the requested data address is inside slave buffer - if (driver.slave_instance_.command.addr >= (driver.slave_instance_.databuff_size - driver.slave_instance_.databuff_ro_size)) { - driver.slave_instance_.command.err = SPI_CMD_ERR_ADDRESS; - goto exit; + if (command.addr >= (driver.slave_instance_.databuff_size - driver.slave_instance_.databuff_ro_size)) { + command.err = SPI_CMD_ERR_ADDRESS; + goto dummyreceive; } // check data length - if ( (data_len > (driver.slave_instance_.databuff_size - driver.slave_instance_.databuff_ro_size)) || - (data_len < ((driver.slave_instance_.command.cmd == SPI_CMD_WRITE_DATA_BLOCK_CSUM) ? 3 : 1)) || - ((driver.slave_instance_.command.addr + data_len) > (driver.slave_instance_.databuff_size - driver.slave_instance_.databuff_ro_size)) ) { - driver.slave_instance_.command.err = SPI_CMD_ERR_LENGTH; - goto exit; + if ( (command.len > (driver.slave_instance_.databuff_size - driver.slave_instance_.databuff_ro_size)) || + ((command.addr + command.len) > (driver.slave_instance_.databuff_size - driver.slave_instance_.databuff_ro_size)) ) { + command.err = SPI_CMD_ERR_LENGTH; + goto dummyreceive; } - if (driver.slave_instance_.command.cmd == SPI_CMD_WRITE_DATA_BLOCK_CSUM) { - // backup two bytes which will be overwritten with checksum - csum_bkp[0] = *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len - 2); - csum_bkp[1] = *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len - 1); + + uint8_t *recv_buf = NULL; + if (command.len > SPI_SLAVE_TRANS_THRESHOLD) { + // allocate temporary buffer for transfer + tmp_buffer = alloc_buffer(command.len, NULL, 0, 0); + if (tmp_buffer == NULL) { + driver.slave_instance_.command.err = SPI_CMD_ERR_MEMORY; + goto dummyreceive; + } + recv_buf = (uint8_t *)tmp_buffer; + + srcs[0] = (void *)&spi_handle.dr[0]; + dests[0] = tmp_buffer; + + // prepare receive + set_bit_mask(&spi_handle.ctrlr0, 1 << SLAVE_OUTPUT_ENABLE_BITS, 1 << SLAVE_OUTPUT_ENABLE_BITS); // Disable SPI Slave output + set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 2 << driver.tmod_off_); // Set Receive only mode + spi_handle.dmacr = 0x01; // Receive DMA Enable + spi_handle.imr = 0x00; // Disable SPI interrupts + spi_handle.ssienr = 0x01; // SPI enable + + dma_set_request_source(driver.slave_instance_.dma, driver.dma_req_); + spi_handle.dmacr = 0x01; + + command.transfer_time = read_csr64(mcycle); + + dma_loop_async(driver.slave_instance_.dma, srcs, 1, dests, 1, false, true, 4, data_length, 1, + NULL, userdata, driver.slave_instance_.dma_event, &stop_signal); + + set_handshake(driver.slave_instance_.handshake, GPIO_PV_LOW); + + _wait_slave_transfer_finish(userdata, spi_handle.rxflr); + } + else { + // short blocks are received without using DMA + uint8_t buf[data_length]; + recv_buf = buf; + receive_no_dma(userdata, buf, data_length); } - // slave buffer position - uint8_t *new_data = (uint8_t *)(driver.slave_instance_.databuff_ptr+driver.slave_instance_.command.addr); - - driver.slave_instance_.command.err = SPI_CMD_ERR_OK; - size_t tx_frames = data_len / data_width; - spi_handle.ctrlr0 = (0x0 << driver.mod_off_) | (0x1 << slv_oe) | ((driver.slave_instance_.data_bit_length - 1) << driver.dfs_off_); - spi_handle.dmacr = 0x01; - spi_handle.imr = 0x00; - spi_handle.ssienr = 0x01; - - end_time_us = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - dma_set_request_source(driver.slave_instance_.dma, driver.dma_req_); - spi_handle.dmacr = 0x01; - dma_transmit_async(driver.slave_instance_.dma, &spi_handle.dr[0], new_data, 0, 1, data_width, tx_frames, 4, driver.slave_instance_.dma_event); - - if (_wait_transfer_finish(userdata)) { - // === data received === - if (driver.slave_instance_.command.cmd == SPI_CMD_WRITE_DATA_BLOCK_CSUM) { + + if (command.err == SPI_CMD_ERR_OK) { + if (tmp_buffer != NULL) { + // data received in 32-bit temporary buffer, convert it to 8-bit + uint8_t *buf8 = (uint8_t *)tmp_buffer; + uint32_t *buf32 = (uint32_t *)tmp_buffer; + for (int i=0; i<(command.len + 2); i++) { + buf8[i] = (uint8_t)buf32[i]; + } + } + + if (with_crc) { // received data with checksum, test checksum - if (driver.slave_instance_.csum_callback) { - uint16_t *rcsum = (uint16_t *)(new_data + data_len-2); // received checksum - uint16_t csum = driver.slave_instance_.csum_callback((const uint8_t *)new_data, data_len-2); // calculated checksum - if (csum != *rcsum) driver.slave_instance_.command.err = SPI_CMD_ERR_DATA_CSUM; + uint16_t rcsum = *((uint8_t *)((uint8_t *)recv_buf + driver.slave_instance_.command.len)); + rcsum |= *((uint8_t *)((uint8_t *)recv_buf + driver.slave_instance_.command.len + 1)) << 8; + // calculated checksum + command.crc16 = hal_crc16((const void*)recv_buf, command.len, 0); + if (command.crc16 == rcsum) { + // copy received data to the slave buffer + xSemaphoreTake(driver.slave_instance_.slave_mutex, 2); + memcpy((uint8_t *)((uint8_t *)driver.slave_instance_.databuff_ptr+command.addr), recv_buf, command.len); + xSemaphoreGive(driver.slave_instance_.slave_mutex); } - // restore two bytes overwritten with checksum - *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len - 2) = csum_bkp[0]; - *(driver.slave_instance_.databuff_ptr + driver.slave_instance_.command.addr + data_len - 1) = csum_bkp[1]; + else command.err = SPI_CMD_ERR_DATA_CSUM; } + else { + // copy received data to the slave buffer without check + xSemaphoreTake(driver.slave_instance_.slave_mutex, 2); + memcpy((uint8_t *)((uint8_t *)driver.slave_instance_.databuff_ptr+command.addr), recv_buf, command.len); + xSemaphoreGive(driver.slave_instance_.slave_mutex); + } + } + + if (wr_confirm) { + memset(driver.slave_instance_.cmd_status, 0, SLAVE_COMMAND_STATUS_LENGTH); + set_confirm_data(userdata, driver.slave_instance_.cmd_status); + uint16_t crc = hal_crc16((const void*)(driver.slave_instance_.cmd_status), SLAVE_COMMAND_STATUS_LENGTH-2, 0); + driver.slave_instance_.cmd_status[SLAVE_COMMAND_STATUS_LENGTH-2] = crc & 0xff; + driver.slave_instance_.cmd_status[SLAVE_COMMAND_STATUS_LENGTH-1] = crc >> 8; } } - //------------------------------------------------------------------ - else if (driver.slave_instance_.command.cmd == SPI_CMD_TEST_COMMAND) + //---------------------------------------- + else if (command.cmd == SPI_CMD_READ_INFO) { - // --------------------------------------------------------------------------------- - // Send the requested number of byte values specified in the command's address field - // --------------------------------------------------------------------------------- + // ----------------------------------------------------------------- + // Send the SPI slave info to the master (19 bytes + 2-byte checksum + // ----------------------------------------------------------------- - driver.slave_instance_.command.err = SPI_CMD_ERR_OK; + if ((command.len != 22) || (!with_crc)) { + command.err = SPI_CMD_ERR_LENGTH; + goto dummysend; + } - size_t tx_frames = (driver.slave_instance_.command.len / data_width); // + 8; - spi_handle.ctrlr0 = (0x0 << driver.mod_off_) | (0x0 << slv_oe) | ((driver.slave_instance_.data_bit_length - 1) << driver.dfs_off_); - set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 1 << driver.tmod_off_); - spi_handle.dmacr = 0x02; - spi_handle.imr = 0x00; - spi_handle.ssienr = 0x01; + uint8_t buf[24+command.dummy_bytes] = { 0 }; + uint8_t * slave_info = buf + command.dummy_bytes; + for (int i=0; i> 8) & 0xff; + slave_info[14] = (driver.slave_instance_.databuff_size >> 16) & 0xff; + slave_info[15] = driver.slave_instance_.databuff_ro_size & 0xff; + slave_info[16] = (driver.slave_instance_.databuff_ro_size >> 8) & 0xff; + slave_info[17] = (driver.slave_instance_.databuff_ro_size >> 16) & 0xff; + slave_info[18] = driver.slave_instance_.crc_speed & 0xff; + slave_info[19] = (driver.slave_instance_.crc_speed >> 8) & 0xff; + slave_info[20] = (driver.slave_instance_.crc_speed >> 16) & 0xff; + slave_info[21] = (uint8_t)(driver.slave_instance_.handshake >= 0); + command.crc16 = hal_crc16((const void*)(slave_info), 22, 0); + slave_info[22] = command.crc16 & 0xff; + slave_info[23] = command.crc16 >> 8; + + send_no_dma(userdata, buf, 24+command.dummy_bytes); + } + //---- unhandled command, return to idle mode ---- + else + { + command.cmd = SPI_CMD_MAX; + command.err = SPI_CMD_ERR_COMMAND; + } + // === Command processing finished === - switch_to_miso(driver.slave_instance_.mosi, driver.slave_instance_.miso); +exit: + if (tmp_buffer) { + if (tmp_buffer < (uint32_t *)0x80000000) tmp_buffer += 0x40000000; + vPortFree(tmp_buffer); + } + // set command execution time + if (command.end_time == 0) command.end_time = read_csr64(mcycle); - end_time_us = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - dma_set_request_source(driver.slave_instance_.dma, driver.dma_req_ + 1); - dma_transmit_async(driver.slave_instance_.dma, &driver.slave_instance_.command.addr, &spi_handle.dr[0], 0, 0, data_width, tx_frames, 1, driver.slave_instance_.dma_event); + // Send the status (transaction result) to the main task + if (driver.slave_instance_.slave_queue != NULL) + xQueueSend(driver.slave_instance_.slave_queue, (void *)&command, 0); - _wait_transfer_finish(userdata); + // ===== Back to IDLE mode =============================================================================== - switch_to_mosi(driver.slave_instance_.mosi, driver.slave_instance_.miso); + atomic_set(&driver.slave_instance_.status, IDLE); + spi_handle.imr = 0x00; // disable interrupts (should already be disabled) + // dummy read, clear spi fifo + while (spi_handle.rxflr > 0) { + data_length = spi_handle.dr[0]; } - //--------------------------------------------------------------- - else if (driver.slave_instance_.command.cmd == SPI_CMD_READ_INFO) - { - // ------------------------------------------------------------------ - // Send the SPI slave info to the master (16 bytes + 2-byte checksum) - // ------------------------------------------------------------------ - - uint16_t csum = 0; - volatile uint8_t slave_info[18] = { 0 }; - memcpy((uint8_t *)slave_info, SPI_SLAVE_INFO, 9); - slave_info[10] = driver.slave_instance_.databuff_size & 0xff; - slave_info[11] = (driver.slave_instance_.databuff_size >> 8) & 0xff; - slave_info[12] = (driver.slave_instance_.databuff_size >> 16) & 0xff; - slave_info[13] = driver.slave_instance_.databuff_ro_size & 0xff; - slave_info[14] = (driver.slave_instance_.databuff_ro_size >> 8) & 0xff; - slave_info[15] = (driver.slave_instance_.databuff_ro_size >> 16) & 0xff; - if (driver.slave_instance_.csum_callback) { - csum = driver.slave_instance_.csum_callback((const uint8_t *)(slave_info), 16); - } - slave_info[16] = csum & 0xff; - slave_info[17] = (csum >> 8) & 0xff; + spi_handle.ssienr = 0x00; // SPI disable (should be already disabled) + // prepare for receive + set_bit_mask(&spi_handle.ctrlr0, 1 << SLAVE_OUTPUT_ENABLE_BITS, 1 << SLAVE_OUTPUT_ENABLE_BITS); // Disable SPI Slave output + set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 2 << driver.tmod_off_); // Set Receive only mode + spi_handle.dmacr = 0x00; // Disable DMA Receive&Transmit + spi_handle.imr = 0x00; // Disable SPI interrupts + spi_handle.rxftlr = 0; // Enable interrupt after 1st received byte - driver.slave_instance_.command.err = SPI_CMD_ERR_OK; + spi_handle.imr = 0x10; // enable spi interrupt - size_t tx_frames = (18 / data_width); // + 8; - spi_handle.ctrlr0 = (0x0 << driver.mod_off_) | (0x0 << slv_oe) | ((driver.slave_instance_.data_bit_length - 1) << driver.dfs_off_); - set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 1 << driver.tmod_off_); - spi_handle.dmacr = 0x02; - spi_handle.imr = 0x00; - spi_handle.ssienr = 0x01; + set_handshake(driver.slave_instance_.handshake, GPIO_PV_HIGH); + if (driver.slave_instance_.command.err != SPI_CMD_ERR_EXIT) spi_handle.ssienr = 0x01; // enable spi - switch_to_miso(driver.slave_instance_.mosi, driver.slave_instance_.miso); + // ======================================================================================================= - end_time_us = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - dma_set_request_source(driver.slave_instance_.dma, driver.dma_req_ + 1); - dma_transmit_async(driver.slave_instance_.dma, slave_info, &spi_handle.dr[0], 1, 0, data_width, tx_frames, 1, driver.slave_instance_.dma_event); + return; // spi_slave_command_mode -> spi slave task - _wait_transfer_finish(userdata); +dummysend: + srcs[0] = (void *)spi_slave_dummy_bytes; + dests[0] = (void *)&spi_handle.dr[0]; - switch_to_mosi(driver.slave_instance_.mosi, driver.slave_instance_.miso); - } - //----------------------------------------------------------------- - else if (driver.slave_instance_.command.cmd == SPI_CMD_LAST_STATUS) - { - // ---------------------------------------------------- - // Send the SPI slave last command status to the master - // ---------------------------------------------------- - - uint16_t csum = 0; - int data_len = sizeof(spi_slave_command_t); - volatile uint8_t slave_status[data_len+2] = { 0 }; // 26 bytes - memcpy((uint8_t *)slave_status, (void *)&driver.slave_instance_.last_command, data_len); - if (driver.slave_instance_.csum_callback) { - csum = driver.slave_instance_.csum_callback((const uint8_t *)(slave_status), sizeof(spi_slave_command_t)); - } - slave_status[sizeof(spi_slave_command_t)] = csum & 0xff; - slave_status[sizeof(spi_slave_command_t)+1] = (csum >> 8) & 0xff; + prepare_send(userdata); - driver.slave_instance_.command.err = SPI_CMD_ERR_OK; + dma_loop_async(driver.slave_instance_.dma, srcs, 1, dests, 1, false, false, 4, data_length, 1, + NULL, userdata, driver.slave_instance_.dma_event, &stop_signal); + set_handshake(driver.slave_instance_.handshake, GPIO_PV_LOW); - size_t tx_frames = (data_len+2) / data_width; // + 8; - spi_handle.ctrlr0 = (0x0 << driver.mod_off_) | (0x0 << slv_oe) | ((driver.slave_instance_.data_bit_length - 1) << driver.dfs_off_); - set_bit_mask(&spi_handle.ctrlr0, 3 << driver.tmod_off_, 1 << driver.tmod_off_); - spi_handle.dmacr = 0x02; - spi_handle.imr = 0x00; - spi_handle.ssienr = 0x01; + _wait_slave_transfer_finish(userdata, spi_handle.txflr); - switch_to_miso(driver.slave_instance_.mosi, driver.slave_instance_.miso); + switch_to_mosi(driver.slave_instance_.mosi, driver.slave_instance_.miso); + goto exit; - end_time_us = read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000); - dma_set_request_source(driver.slave_instance_.dma, driver.dma_req_ + 1); - dma_transmit_async(driver.slave_instance_.dma, slave_status, &spi_handle.dr[0], 1, 0, data_width, tx_frames, 1, driver.slave_instance_.dma_event); +dummyreceive: + dests[0] = (void *)spi_slave_dummy_bytes; + srcs[0] = (void *)&spi_handle.dr[0]; - _wait_transfer_finish(userdata); + dma_loop_async(driver.slave_instance_.dma, srcs, 1, dests, 1, false, false, 4, data_length, 1, + NULL, userdata, driver.slave_instance_.dma_event, &stop_signal); + set_handshake(driver.slave_instance_.handshake, GPIO_PV_LOW); - switch_to_mosi(driver.slave_instance_.mosi, driver.slave_instance_.miso); - } - //---- unhandled command, return to idle mode ---- - else - { - driver.slave_instance_.command.err = SPI_CMD_ERR_COMMAND; - } - -exit: - // set command execution time - driver.slave_instance_.command.time = (read_csr64(mcycle) / (uint64_t)(sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)/1000000)) - driver.slave_instance_.command.time; - // backup the command - if (driver.slave_instance_.command.cmd != SPI_CMD_LAST_STATUS) - memcpy((void *)&driver.slave_instance_.last_command, (void *)&driver.slave_instance_.command, sizeof(spi_slave_command_t)); - // execute the callback function if set - if (driver.slave_instance_.callback != NULL) driver.slave_instance_.callback((void *)&driver.slave_instance_.command); - - LOGV(SLAVE_TAG, "Prepare time: %lu us", end_time_us - time_us); - spi_slave_idle_mode(userdata, (driver.slave_instance_.command.err != SPI_CMD_ERR_FATAL)); - return; + _wait_slave_transfer_finish(userdata, spi_handle.rxflr); + goto exit; } + // ==== End of SPI Slave functions ===================================================== + + //--------------------------------------------- + void setup_device(k_spi_device_driver &device); + //------------------- volatile spi_t &spi() { return spi_; } + //------------------------------------- + volatile spi_slave_command_t &command() + { + return slave_instance_.command; + } + //-------------------------------------------------------------------------------------- static void write_inst_addr(volatile uint32_t *dr, const uint8_t **buffer, size_t width) { @@ -908,25 +1457,23 @@ static int _wait_DMA_transfer(SemaphoreHandle_t dma_event1, SemaphoreHandle_t dm if (tcurr > tmo) { // timeout if (check1) { - dma_stop(dma_trans1); - if (xSemaphoreTake(dma_event1, 500 / portTICK_PERIOD_MS) == pdTRUE) { + if (xSemaphoreTake(dma_event1, 100 / portTICK_PERIOD_MS) == pdTRUE) { ret = 0; - LOGW(TAG, "DMA transfer not finished, DMA stopped"); + LOGW(TAG, "DMA transfer not finished, stopped"); } else { ret = -1; - LOGE(TAG, "DMA transfer not finished, DMA NOT stopped"); + LOGE(TAG, "DMA transfer not finished, NOT stopped"); } } if (check2) { - dma_stop(dma_trans2); - if (xSemaphoreTake(dma_event2, 500 / portTICK_PERIOD_MS) == pdTRUE) { + if (xSemaphoreTake(dma_event2, 100 / portTICK_PERIOD_MS) == pdTRUE) { ret = 0; - LOGW(TAG, "DMA transfer not finished, DMA stopped"); + LOGW(TAG, "DMA transfer not finished, stopped"); } else { ret = -1; - LOGE(TAG, "DMA transfer not finished, DMA NOT stopped"); + LOGE(TAG, "DMA transfer not finished, NOT stopped"); } } break; @@ -1005,7 +1552,6 @@ int k_spi_driver::read(k_spi_device_driver &device, gsl::span buffer) write_inst_addr(spi_.dr, &buffer_it, device.addr_width_); spi_.ser = device.chip_select_mask_; - //configASSERT(pdTRUE == xSemaphoreTake(event_read, SPI_DMA_BLOCK_TIME)); int dma_ret = _wait_DMA_transfer(event_read, NULL, dma_read, 0, SPI_DMA_BLOCK_TIME); configASSERT(dma_ret >= 0); if (dma_ret < 1) ret = -1; @@ -1083,7 +1629,6 @@ int k_spi_driver::write(k_spi_device_driver &device, gsl::span bu dma_transmit_async(dma_write, buffer_write, &spi_.dr[0], 1, 0, device.buffer_width_, tx_frames, 4, event_write); spi_.ser = device.chip_select_mask_; - //configASSERT(pdTRUE == xSemaphoreTake(event_write, SPI_DMA_BLOCK_TIME)); int dma_ret = _wait_DMA_transfer(event_write, NULL, dma_write, 0, SPI_DMA_BLOCK_TIME); configASSERT(dma_ret >= 0); if (dma_ret < 1) ret = -1; @@ -1233,7 +1778,6 @@ int k_spi_driver::read_write(k_spi_device_driver &device, gsl::span= 0); if (dma_ret < 1) ret = -1; @@ -1271,7 +1815,6 @@ void k_spi_driver::fill(k_spi_device_driver &device, uint32_t instruction, uint3 dma_transmit_async(dma_write, &value, &spi_.dr[0], 0, 0, sizeof(uint32_t), count, 4, event_write); spi_.ser = device.chip_select_mask_; - //configASSERT(xSemaphoreTake(event_write, SPI_DMA_BLOCK_TIME) == pdTRUE); int dma_ret = _wait_DMA_transfer(event_write, NULL, dma_write, 0, SPI_DMA_BLOCK_TIME); configASSERT(dma_ret >= 0); diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/devices.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/devices.h index 298be35..70f14aa 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/devices.h +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/devices.h @@ -291,17 +291,15 @@ void i2s_stop(handle_t file); * @brief Set spi slave configuration * * @param[in] file The SPI controller handle - * @param[in] data_bit_length Spi data bit length,suport 8/16/32 bit. * @param[in] data SPI slave device data buffer pointer. * @param[in] len The length of SPI slave device data buffer. * @param[in] ro_len The length of read only area at the end of the data buffer. - * @param[in] callback Callback of spi slave, called after processing command. - * @param[in] csum_callback Callback function fo processing the data csum + * @param[in] queue Queue for passing transaction result/status to the main task. * @param[in] priority Internal FreeRTOS task priority. * - * @return Void + * @return true on success, false if failed */ -void spi_slave_config(handle_t file, size_t data_bit_length, uint8_t *data, uint32_t len, uint32_t ro_len, spi_slave_receive_callback_t callback, spi_slave_csum_callback_t csum_callback, int priority, int mosi, int miso); +bool spi_slave_config(handle_t file, void *data, uint32_t len, uint32_t ro_len, QueueHandle_t queue, int priority, int mosi, int miso, int handshake); /** * LoBo @@ -313,6 +311,74 @@ void spi_slave_config(handle_t file, size_t data_bit_length, uint8_t *data, uint */ void spi_slave_deinit(handle_t file); +/** + * LoBo + * @brief Set SPI Slave handshake pin level (if used) + * + * @param[in] file The SPI controller handle + * @param[in] value Handshake pin level or pulse interval + * + * @return true if executed, false if not + */ +bool spi_slave_set_handshake(handle_t file, uint16_t value); + +/** + * LoBo + * @brief Set content of the slave buffer + * 'address' and 'size' must be checked to fit inside the buffer + * before calling this function! + * + * @param[in] file The SPI controller handle + * @param[in] buffer pointer to the buffer from which to copy to spi slave buffer + * @param[in] addr start address inside spi slave buffer + * @param[in] size number of bytes to copy + * + * @return true if executed, false if not + */ +bool spi_slave_set_buffer(handle_t file, uint8_t *buffer, uint32_t addr, uint32_t size); + +/** + * LoBo + * @brief Set content of the slave read buffer + * + * @param[in] file The SPI controller handle + * @param[in] buffer pointer to the buffer from which to copy to spi slave read buffer + * buffer size must be exactly 16 bytes + * + * @return true if executed, false if not + */ +bool spi_slave_set_read_buffer(handle_t file, uint8_t *buffer); + +/** + * LoBo + * @brief Set content of the slave buffer to 'fill_byte' value + * 'address' and 'size' must be checked to fit inside the buffer + * before calling this function! + * + * @param[in] file The SPI controller handle + * @param[in] fill_byte byte value to fill the spi buffer with + * @param[in] addr start address inside spi slave buffer + * @param[in] size number of bytes to set + * + * @return true if executed, false if not + */ +bool spi_slave_fill_buffer(handle_t file, uint8_t fill_byte, uint32_t addr, uint32_t size); + +/** + * LoBo + * @brief Get content of the slave buffer + * 'address' and 'size' must be checked to fit inside the buffer + * before calling this function! + * + * @param[in] file The SPI controller handle + * @param[in] buffer pointer to the buffer to which to copy from spi slave buffer + * @param[in] addr start address inside spi slave buffer + * @param[in] size number of bytes to copy + * + * @return true if executed, false if not + */ +bool spi_slave_get_buffer(handle_t file, uint8_t *buffer, uint32_t addr, uint32_t size); + /** * LoBo * @brief Set spi master configuration diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/kernel/driver.hpp b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/kernel/driver.hpp index f2de7ba..af2a3da 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/kernel/driver.hpp +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/kernel/driver.hpp @@ -260,8 +260,13 @@ class spi_driver : public driver public: virtual object_ptr get_device(spi_mode_t mode, spi_frame_format_t frame_format, uint32_t chip_select_mask, uint32_t data_bit_length) = 0; // LoBo: - virtual void slave_config(size_t data_bit_length, uint8_t *data, uint32_t len, uint32_t ro_len, spi_slave_receive_callback_t callback, spi_slave_csum_callback_t csum_callback, int priority, int mosi, int miso) = 0; + virtual bool slave_config(void *data, uint32_t len, uint32_t ro_len, QueueHandle_t queue, int priority, int mosi, int miso, int handshake) = 0; virtual void slave_deinit() = 0; + virtual bool slave_set_handshake(uint16_t value) = 0; + virtual bool slave_set_buffer(uint8_t *buffer, uint32_t addr, uint32_t size) = 0; + virtual bool slave_set_read_buffer(uint8_t *buffer) = 0; + virtual bool slave_fill_buffer(uint8_t fill_byte, uint32_t addr, uint32_t size) = 0; + virtual bool slave_get_buffer(uint8_t *buffer, uint32_t addr, uint32_t size) = 0; }; class dvp_driver : public driver diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/osdefs.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/osdefs.h index dc34555..5f441dc 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/osdefs.h +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/include/osdefs.h @@ -132,13 +132,14 @@ typedef enum _spi_inst_addr_trans_mode // LoBo: changed typedef enum { SPI_CMD_NO_COMMAND, - SPI_CMD_TEST_COMMAND, - SPI_CMD_READ_INFO, - SPI_CMD_LAST_STATUS, - SPI_CMD_WRITE_DATA_BLOCK, - SPI_CMD_WRITE_DATA_BLOCK_CSUM, SPI_CMD_READ_DATA_BLOCK, - SPI_CMD_READ_DATA_BLOCK_CSUM, + SPI_CMD_WRITE_DATA_BLOCK, + SPI_CMD_READ_INFO, + SPI_CMD_WRSTAT, + SPI_CMD_WRSTAT_CONFIRM, + SPI_CMD_RDSTAT, + SPI_CMD_READ_TRANS, + SPI_CMD_STATUS_TRANS, SPI_CMD_MAX, } spi_slave_command_e; @@ -152,22 +153,28 @@ typedef enum { SPI_CMD_ERR_LENGTH, SPI_CMD_ERR_TIMEOUT, SPI_CMD_ERR_ERROR, - SPI_CMD_ERR_FATAL, + SPI_CMD_ERR_EXIT, + SPI_CMD_ERR_NOTALIGNED, + SPI_CMD_ERR_MEMORY, SPI_CMD_ERR_MAX, } spi_slave_command_errors_t; // Lobo: changed typedef struct { - uint8_t cmd; - spi_slave_command_errors_t err; - uint32_t addr; - uint32_t len; - uint64_t time; -} spi_slave_command_t; - -typedef int (*spi_slave_receive_callback_t)(void *ctx); -typedef uint16_t (*spi_slave_csum_callback_t)(const uint8_t *buf, uint32_t count); + uint8_t cmd; + uint8_t opt; + uint8_t dummy_bytes; + uint8_t err; + uint8_t user_data[12]; + uint16_t crc16; + uint32_t addr; + uint32_t len; + uint64_t start_time; + uint64_t command_time; + uint64_t transfer_time; + uint64_t end_time; +} spi_slave_command_t; // size=40 typedef enum _video_format { diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/kernel/devices.cpp b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/kernel/devices.cpp index f1863a9..e257018 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/kernel/devices.cpp +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/freertos/kernel/devices.cpp @@ -485,19 +485,49 @@ void i2s_stop(handle_t file) /* SPI */ // LoBo: changed function -void spi_slave_config(handle_t file, size_t data_bit_length, uint8_t *data, uint32_t len, uint32_t ro_len, spi_slave_receive_callback_t callback, spi_slave_csum_callback_t csum_callback, int priority, int mosi, int miso) +bool spi_slave_config(handle_t file, void *data, uint32_t len, uint32_t ro_len, QueueHandle_t queue, int priority, int mosi, int miso, int handshake) { COMMON_ENTRY(spi); - spi->slave_config(data_bit_length, data, len, ro_len, callback, csum_callback, priority, mosi, miso); + return spi->slave_config(data, len, ro_len, queue, priority, mosi, miso, handshake); } -// LoBo: added function +// LoBo: added functions void spi_slave_deinit(handle_t file) { COMMON_ENTRY(spi); spi->slave_deinit(); } +bool spi_slave_set_handshake(handle_t file, uint16_t value) +{ + COMMON_ENTRY(spi); + return spi->slave_set_handshake(value); +} + +bool spi_slave_set_buffer(handle_t file, uint8_t *buffer, uint32_t addr, uint32_t size) +{ + COMMON_ENTRY(spi); + return spi->slave_set_buffer(buffer, addr, size); +} + +bool spi_slave_set_read_buffer(handle_t file, uint8_t *buffer) +{ + COMMON_ENTRY(spi); + return spi->slave_set_read_buffer(buffer); +} + +bool spi_slave_fill_buffer(handle_t file, uint8_t fill_byte, uint32_t addr, uint32_t size) +{ + COMMON_ENTRY(spi); + return spi->slave_fill_buffer(fill_byte, addr, size); +} + +bool spi_slave_get_buffer(handle_t file, uint8_t *buffer, uint32_t addr, uint32_t size) +{ + COMMON_ENTRY(spi); + return spi->slave_get_buffer(buffer, addr, size); +} + handle_t spi_get_device(handle_t file, spi_mode_t mode, spi_frame_format_t frame_format, uint32_t chip_select_mask, uint32_t data_bit_length) { COMMON_ENTRY(spi); diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/fpioa.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/fpioa.c index 29dea63..bec5c49 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/fpioa.c +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/fpioa.c @@ -5312,6 +5312,15 @@ int fpioa_get_io_driving(int number) return fpioa->io[number].ds; } +uint32_t fpioa_get_pad_di(int number) +{ + /* Check parameters */ + //if (number < 0 || number >= FPIOA_NUM_IO) + // return -1; + + return fpioa->io[number].pad_di; +} + int fpioa_set_function_raw(int number, fpioa_function_t function) { /* Check parameters */ diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/include/fpioa.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/include/fpioa.h index f4809f6..3bd5756 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/include/fpioa.h +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/include/fpioa.h @@ -460,6 +460,9 @@ int fpioa_get_io_driving(int number); */ int fpioa_get_io_by_function(fpioa_function_t function); + +uint32_t fpioa_get_pad_di(int number); + #ifdef __cplusplus } #endif diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/include/utility.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/include/utility.h index 1205232..2bdbe84 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/include/utility.h +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/include/utility.h @@ -12,6 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +// LoBo: added CRC functions + #ifndef _DRIVER_UTILITY_H #define _DRIVER_UTILITY_H @@ -48,16 +51,24 @@ extern "C" (*(volatile uint64_t *)(addr)) = (v); \ } + extern const uint32_t Crc32LookupTable[256]; + extern const uint16_t Crc16LookupTable[256]; + extern const uint8_t Crc8LookupTable[256]; + uint32_t get_bit_mask(volatile uint32_t *bits, uint32_t mask); void set_bit_mask(volatile uint32_t *bits, uint32_t mask, uint32_t value); uint32_t get_bit_idx(volatile uint32_t *bits, uint32_t idx); void set_bit_idx(volatile uint32_t *bits, uint32_t idx, uint32_t value); void busy_wait(uint64_t millionseconds); + uint8_t hal_crc8(const void* data, size_t length, uint8_t previousCrc8); + uint16_t hal_crc16(const void* data, size_t length, uint16_t previousCrc16); + uint32_t hal_crc32(const void* data, size_t length, uint32_t previousCrc32); #ifdef __cplusplus } #endif + #ifdef __cplusplus namespace details diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/utility.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/utility.c index 9c6cb88..c5be505 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/utility.c +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/lib/hal/utility.c @@ -17,6 +17,106 @@ #include "utility.h" #include + +// LoBo: added CRC functions + +//------------------------------------ +const uint32_t Crc32LookupTable[256] = +{ + // note: the first number of every second row corresponds to the half-byte look-up table ! + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, + 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, + 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, + 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, + 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, + 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, + 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, + 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, + 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, + 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, + 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, + 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, + 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, + 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, + 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, +}; + +//------------------------------------ +const uint16_t Crc16LookupTable[256] = +{ + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + +// https://www.maximintegrated.com/en/app-notes/index.mvp/id/27 +const uint8_t Crc8LookupTable[256] = +{ + 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, + 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, + 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, + 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, + 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, + 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, + 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, + 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, + 140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205, + 17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80, + 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238, + 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, + 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, + 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, + 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, + 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 +}; + + uint32_t get_bit_mask(volatile uint32_t* bits, uint32_t mask) { return (*bits) & mask; @@ -47,3 +147,41 @@ void busy_wait(uint64_t millionseconds) while (clint->mtime - clint_time < nop_all) ; } + +//--------------------------------------------------------------------- +uint8_t hal_crc8(const void* data, size_t length, uint8_t previousCrc8) +{ + uint8_t crc = previousCrc8; + const uint8_t *pbuf = (const uint8_t *)data; + while (length--) { + crc = Crc8LookupTable[crc ^ *pbuf++]; + } + return crc; +} + +//------------------------------------------------------------------------- +uint16_t hal_crc16(const void* data, size_t length, uint16_t previousCrc16) +{ + uint16_t crc = ~previousCrc16; + const uint8_t *pbuf = (const uint8_t *)data; + + while (length--) { + crc = (crc<<8) ^ Crc16LookupTable[((crc>>8) ^ *pbuf++) & 0x00FF]; + } + return crc; +} + +// Compute CRC32 (standard algorithm) +//------------------------------------------------------------------------- +uint32_t hal_crc32(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint8_t* current = (const uint8_t*) data; + + while (length-- != 0) { + crc = (crc >> 8) ^ Crc32LookupTable[(crc & 0xFF) ^ *current++]; + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/CMakeLists.txt b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/CMakeLists.txt index ab104f1..6edbd51 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/CMakeLists.txt +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(fatfs) add_subdirectory(lwip) add_subdirectory(mbedtls) +#add_subdirectory(curl) diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/Filelists.cmake b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/Filelists.cmake index 8c07647..6a9eece 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/Filelists.cmake +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/Filelists.cmake @@ -141,6 +141,12 @@ set(lwipppp_SRCS ${LWIP_DIR}/src/netif/ppp/polarssl/sha256.c ) +# FTP +# LoBo: added lwftp +set(lwftp_SRCS + ${LWIP_DIR}/src/lwftp/lwftp.c +) + # SNMPv3 agent set(lwipsnmp_SRCS ${LWIP_DIR}/src/apps/snmp/snmp_asn1.c @@ -230,6 +236,7 @@ set(lwipnoapps_SRCS ${lwipnetif_SRCS} ${lwipsixlowpan_SRCS} ${lwipppp_SRCS} + ${lwftp_SRCS} ) # LWIPAPPFILES: All LWIP APPs @@ -255,4 +262,4 @@ set(LWIP_INCLUDE_DIRS ${LWIP_DIR}/src/include) add_library(lwipcore EXCLUDE_FROM_ALL ${lwipnoapps_SRCS} ${lwipallapps_SRCS}) target_compile_options(lwipcore PRIVATE ${LWIP_COMPILER_FLAGS}) target_compile_definitions(lwipcore PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS}) -target_include_directories(lwipcore PUBLIC ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS}) +target_include_directories(lwipcore PUBLIC ${LWIP_INCLUDE_DIRS} ${LWIP_MBEDTLS_INCLUDE_DIRS} ${LWIP_DIR}/../../lib/utils/include ${LWIP_DIR}/../../lib/hal/include) diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/include/lwip/arch.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/include/lwip/arch.h index 202029e..36f5868 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/include/lwip/arch.h +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/include/lwip/arch.h @@ -46,6 +46,7 @@ #endif #include "arch/cc.h" +#include "syslog.h" /** * @defgroup compiler_abstraction Compiler/platform abstraction @@ -89,8 +90,12 @@ * systems, this should be defined to something less resource-consuming. */ #ifndef LWIP_PLATFORM_ASSERT +/* #define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) +*/ +// LoBo: do not abort on errors, only print error log +#define LWIP_PLATFORM_ASSERT(x) do { LOGE("[lwip]", "Error '%s' at line %d", x, __LINE__); } while(0) #include #include #endif diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/include/lwip/lwftp/lwftp.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/include/lwip/lwftp/lwftp.h new file mode 100644 index 0000000..9270884 --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/include/lwip/lwftp/lwftp.h @@ -0,0 +1,109 @@ +/* + * lwftp.h : a lightweight FTP client using raw API of LWIP + * + * Copyright (c) 2014 GEZEDO + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Laurent GONZALEZ + * + */ + +#ifndef LWFTP_H +#define LWFTP_H + +#include "lwip/opt.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum lwftp_results { + LWFTP_RESULT_OK=0, + LWFTP_RESULT_INPROGRESS, + LWFTP_RESULT_LOGGED, + LWFTP_RESULT_ERR_UNKNOWN, /** Unknown error */ + LWFTP_RESULT_ERR_ARGUMENT, /** Wrong argument */ + LWFTP_RESULT_ERR_MEMORY, /** Out of memory */ + LWFTP_RESULT_ERR_CONNECT, /** Connection to server failed */ + LWFTP_RESULT_ERR_HOSTNAME, /** Failed to resolve server hostname */ + LWFTP_RESULT_ERR_CLOSED, /** Connection unexpectedly closed by remote server */ + LWFTP_RESULT_ERR_TIMEOUT, /** Connection timed out (server didn't respond in time) */ + LWFTP_RESULT_ERR_SRVR_RESP, /** Server responded with an unknown response code */ + LWFTP_RESULT_ERR_INTERNAL, /** Internal network stack error */ + LWFTP_RESULT_ERR_LOCAL, /** Local storage error */ + LWFTP_RESULT_ERR_FILENAME /** Remote host could not find file */ +}; + +/** LWFTP control connection state */ +typedef enum { + LWFTP_CLOSED=0, + LWFTP_CONNECTED, + LWFTP_USER_SENT, + LWFTP_PASS_SENT, + LWFTP_LOGGED, + LWFTP_TYPE_SENT, + LWFTP_PASV_SENT, + LWFTP_RETR_SENT, + LWFTP_STOR_SENT, + LWFTP_XFERING, + LWFTP_DATAEND, + LWFTP_QUIT, + LWFTP_QUIT_SENT, + LWFTP_CLOSING, +} lwftp_state_t; + +/** LWFTP session structure */ +typedef struct { + // User interface + ip_addr_t server_ip; + u16_t server_port; + const char *remote_path; + const char *user; + const char *pass; + void *handle; + uint (*data_source)(void*, const char**, uint); + uint (*data_sink)(void*, const char*, uint); + void (*done_fn)(void*, int); + uint timeout; + // Internal data + lwftp_state_t control_state; + lwftp_state_t target_state; + lwftp_state_t data_state; + struct tcp_pcb *control_pcb; + struct tcp_pcb *data_pcb; +} lwftp_session_t; + +// LWFTP API +err_t lwftp_connect(lwftp_session_t *s); +err_t lwftp_store(lwftp_session_t *s); +err_t lwftp_retrieve(lwftp_session_t *s); +void lwftp_close(lwftp_session_t *s); + +#ifdef __cplusplus +} +#endif + +#endif // LWFTP_H diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/lwftp/README.md b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/lwftp/README.md new file mode 100644 index 0000000..2dd83cf --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/lwftp/README.md @@ -0,0 +1,139 @@ +# Overview + +A lightweight FTP client using raw API of LWIP + +This client is designed as a state machine with a very low level +interface. It can be used as a library to build smarter clients with +more features. + +The state machine supports 4 basic operations: +* connect +* store +* retrieve +* close + +LWFTP requires the remote server to support binary transfer and +passive connection. + +#### Notes on data callbacks + +There is no storage back-end. The requester provides a callback to +source data. +* The callback is called once with a non null pointer to (char*), to be +used by the actual storage backend to write the location of data. The +return value is the length of available data, limited to the value of +argument maxlen. +* When the callback is called with a NULL pointer to (char*), the maxlen +argument is the number of bytes successfully sent since last call. This +shall be used by the storage backend as an acknowledge. + +# Asynchronous example +``` +static void ftp_retr_callback(void *arg, int result) +{ + lwftp_session_t *s = (lwftp_session_t)arg; + + if ( result != LWFTP_RESULT_OK ) { + LOG_ERROR("retr failed (%d)", result); + return lwftp_close(s); + } + // Test is done + lwftp_close(s); +} + +static uint data_sink(void *arg, const char* ptr, uint len) +{ + static const uint mylen = 12345; + static char * const myconfig = (char*)0x20000000; + static uint offset = 0; + + if (ptr) { + len = min( len, mylen-offset ); + memcpy( myconfig+offset, ptr, len ); + offset += len; + } + return len; +} + +static void ftp_stor_callback(void *arg, int result) +{ + lwftp_session_t *s = (lwftp_session_t)arg; + err_t error; + + if ( result != LWFTP_RESULT_OK ) { + LOG_ERROR("stor failed (%d)", result); + return lwftp_close(s); + } + // Continue with RETR request + s->data_sink = data_sink; + s->done_fn = ftp_retr_callback; + s->remote_path = "configfile"; + error = lwftp_retrieve(s); + if ( error != LWFTP_RESULT_INPROGRESS ) { + LOG_ERROR("lwftp_retrieve failed (%d)", error); + } + // FTP session will continue with RETR and sink callbacks +} + +static uint data_source(void *arg, const char** pptr, uint maxlen) +{ + static const uint mylen = 12345; + static const char * const mydata = (char*)0x20000000; + static uint offset = 0; + uint len = 0; + + // Check for data request or data sent notice + if (pptr) { + len = mylen - offset; + if ( len > maxlen ) len = maxlen; + *pptr = mydata + offset; + } else { + offset += maxlen; + if ( offset > mylen ) offset = mylen; + } + return len; +} + +static void ftp_connect_callback(void *arg, int result) +{ + lwftp_session_t *s = (lwftp_session_t)arg; + err_t error; + + if ( result != LWFTP_RESULT_LOGGED ) { + LOG_ERROR("login failed (%d)", result); + return lwftp_close(s); + } + // Continue with STOR request + s->data_source = data_source; + s->done_fn = ftp_stor_callback; + s->remotepath = "logfile"; + error = lwftp_store(s); + if ( error != LWFTP_RESULT_INPROGRESS ) { + LOG_ERROR("lwftp_store failed (%d)", error); + } + // FTP session will continue with STOR and source callbacks +} + +static void ftp_test(void) +{ + static lwftp_session_t s; // static content for the whole FTP session + err_t error; + + // Initialize session data + memset(&s, 0, sizeof(s)); + IP4_ADDR(&s.server_ip, 192,168,0,31); + s.server_port = 21; + s.done_fn = ftp_connect_callback; + s.user = "username"; + s.pass = "password"; + // We have no extra user data, simply use the session structure + s.handle = &s; + + // Start the connection state machine + error = lwftp_connect(&s); + if ( error != LWFTP_RESULT_INPROGRESS ) { + LOG_ERROR("lwftp_connect failed (%d)", error); + } + // FTP session will continue with the connection callback +} +``` diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/lwftp/lwftp.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/lwftp/lwftp.c new file mode 100644 index 0000000..443fb14 --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/lwip/src/lwftp/lwftp.c @@ -0,0 +1,702 @@ +/* + * lwftp.c : a lightweight FTP client using raw API of LWIP + * + * Copyright (c) 2014 GEZEDO + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Laurent GONZALEZ + * + */ + +#include +#include "lwip/lwftp/lwftp.h" +#include "lwip/tcp.h" +#include "lwip/tcpip.h" +#include + +/** Enable debugging for LWFTP */ +#ifndef LWFTP_DEBUG +#define LWFTP_DEBUG LWIP_DBG_ON +#endif + +#define LWFTP_TRACE (LWFTP_DEBUG|LWIP_DBG_TRACE) +#define LWFTP_STATE (LWFTP_DEBUG|LWIP_DBG_STATE) +#define LWFTP_WARNING (LWFTP_DEBUG|LWIP_DBG_LEVEL_WARNING) +#define LWFTP_SERIOUS (LWFTP_DEBUG|LWIP_DBG_LEVEL_SERIOUS) +#define LWFTP_SEVERE (LWFTP_DEBUG|LWIP_DBG_LEVEL_SEVERE) + +#define PTRNLEN(s) s,(sizeof(s)-1) + +static const char *TAG = "[LWFTP]"; + +static void lwftp_control_process(lwftp_session_t *s, struct tcp_pcb *tpcb, struct pbuf *p); + +/** Close control or data pcb + * @param pointer to lwftp session data + */ +static err_t lwftp_pcb_close(struct tcp_pcb *tpcb) +{ + err_t error; + + tcp_err(tpcb, NULL); + tcp_recv(tpcb, NULL); + tcp_sent(tpcb, NULL); + error = tcp_close(tpcb); + if ( error != ERR_OK ) { + LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:pcb close failure, not implemented\n")); + } + return ERR_OK; +} + +/** Send data + * @param pointer to lwftp session data + * @param pointer to PCB + * @param number of bytes sent + */ +static err_t lwftp_send_next_data(lwftp_session_t *s) +{ + const char *data; + int len = 0; + err_t error = ERR_OK; + + if (s->data_source) { + len = s->data_source(s->handle, &data, s->data_pcb->mss); + if (len) { + error = tcp_write(s->data_pcb, data, len, 0); + if (error!=ERR_OK) { + LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:write failure (%s), not implemented\n",lwip_strerr(error))); + } + } + } + if (!len) { + LWIP_DEBUGF(LWFTP_STATE, ("lwftp:end of file\n")); + lwftp_pcb_close(s->data_pcb); + s->data_pcb = NULL; + } + return ERR_OK; +} + +/** Handle data connection incoming data + * @param pointer to lwftp session data + * @param pointer to PCB + * @param pointer to incoming pbuf + * @param state of incoming process + */ +static err_t lwftp_data_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ + lwftp_session_t *s = (lwftp_session_t*)arg; + if (p) { + if (s->data_sink) { + struct pbuf *q; + for (q=p; q; q=q->next) { + s->data_sink(s->handle, q->payload, q->len); + } + } else { + LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp: sinking %d bytes\n",p->tot_len)); + } + tcp_recved(tpcb, p->tot_len); + pbuf_free(p); + } else { + // NULL pbuf shall lead to close the pcb. Close is postponed after + // the session state machine updates. No need to close right here. + // Instead we kindly tell data sink we are done + if (s->data_sink) { + s->data_sink(s->handle, NULL, 0); + } + } + return ERR_OK; +} + +/** Handle data connection acknowledge of sent data + * @param pointer to lwftp session data + * @param pointer to PCB + * @param number of bytes sent + */ +static err_t lwftp_data_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + lwftp_session_t *s = (lwftp_session_t*)arg; + + if ( s->data_source ) { + s->data_source(s->handle, NULL, len); + } + return lwftp_send_next_data(s); +} + +/** Handle data connection error + * @param pointer to lwftp session data + * @param state of connection + */ +static void lwftp_data_err(void *arg, err_t err) +{ + LWIP_UNUSED_ARG(err); + if (arg != NULL) { + lwftp_session_t *s = (lwftp_session_t*)arg; + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:failed/error connecting for data to server (%s)\n",lwip_strerr(err))); + s->data_pcb = NULL; // No need to de-allocate PCB + if (s->control_state==LWFTP_XFERING) { // gracefully move control session ahead + s->control_state = LWFTP_DATAEND; + lwftp_control_process(s, NULL, NULL); + } + } +} + +/** Process newly connected PCB + * @param pointer to lwftp session data + * @param pointer to PCB + * @param state of connection + */ +static err_t lwftp_data_connected(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + lwftp_session_t *s = (lwftp_session_t*)arg; + + if ( err == ERR_OK ) { + LWIP_DEBUGF(LWFTP_STATE, ("lwftp:connected for data to server\n")); + s->data_state = LWFTP_CONNECTED; + } else { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:err in data_connected (%s)\n",lwip_strerr(err))); + } + return err; +} + +/** Open data connection for passive transfer + * @param pointer to lwftp session data + * @param pointer to incoming PASV response + */ +static err_t lwftp_data_open(lwftp_session_t *s, struct pbuf *p) +{ + err_t error; + char *ptr; + ip_addr_t data_server; + u16_t data_port; + + // Find server connection parameter + ptr = strchr(p->payload, '('); + if (!ptr) return ERR_BUF; + do { + unsigned int a = strtoul(ptr+1,&ptr,10); + unsigned int b = strtoul(ptr+1,&ptr,10); + unsigned int c = strtoul(ptr+1,&ptr,10); + unsigned int d = strtoul(ptr+1,&ptr,10); + IP4_ADDR(&data_server,a,b,c,d); + } while(0); + data_port = strtoul(ptr+1,&ptr,10) << 8; + data_port |= strtoul(ptr+1,&ptr,10) & 255; + if (*ptr!=')') return ERR_BUF; + + // Open data session + tcp_arg(s->data_pcb, s); + tcp_err(s->data_pcb, lwftp_data_err); + tcp_recv(s->data_pcb, lwftp_data_recv); + tcp_sent(s->data_pcb, lwftp_data_sent); + error = tcp_connect(s->data_pcb, &data_server, data_port, lwftp_data_connected); + return error; +} + +/** Send a message to control connection + * @param pointer to lwftp session data + * @param pointer to message string + */ +static err_t lwftp_send_msg(lwftp_session_t *s, const char* msg, size_t len) +{ + err_t error; + + LWIP_DEBUGF(LWFTP_TRACE,("lwftp:sending %s",msg)); + error = tcp_write(s->control_pcb, msg, len, 0); + if ( error != ERR_OK ) { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:cannot write (%s)\n",lwip_strerr(error))); + } + return error; +} + +/** Close data connection + * @param pointer to lwftp session data + * @param result to pass to callback fn (if called) + */ +static void lwftp_data_close(lwftp_session_t *s, int result) +{ + if (s->data_pcb) { + lwftp_pcb_close(s->data_pcb); + s->data_pcb = NULL; + } + if ( s->done_fn ) { + s->done_fn(s->handle, result); + } +} + +/** Close control connection + * @param pointer to lwftp session data + * @param result to pass to callback fn (if called) + */ +static void lwftp_control_close(lwftp_session_t *s, int result) +{ + if (s->data_pcb) { + lwftp_pcb_close(s->data_pcb); + s->data_pcb = NULL; + } + if (s->control_pcb) { + lwftp_pcb_close(s->control_pcb); + s->control_pcb = NULL; + } + s->control_state = LWFTP_CLOSED; + if ( (result >= 0) && s->done_fn ) { + s->done_fn(s->handle, result); + } +} + +/** Main client state machine + * @param pointer to lwftp session data + * @param pointer to PCB + * @param pointer to incoming data + */ +static void lwftp_control_process(lwftp_session_t *s, struct tcp_pcb *tpcb, struct pbuf *p) +{ + uint response = 0; + int result = LWFTP_RESULT_ERR_SRVR_RESP; + + // Try to get response number + if (p) { + response = strtoul(p->payload, NULL, 10); + LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:got response %d\n",response)); + } + + switch (s->control_state) { + case LWFTP_CONNECTED: + if (response>0) { + if (response==220) { + lwftp_send_msg(s, PTRNLEN("USER ")); + lwftp_send_msg(s, s->user, strlen(s->user)); + lwftp_send_msg(s, PTRNLEN("\n")); + s->control_state = LWFTP_USER_SENT; + } else { + s->control_state = LWFTP_QUIT; + } + } + break; + case LWFTP_USER_SENT: + if (response>0) { + if (response==331) { + lwftp_send_msg(s, PTRNLEN("PASS ")); + lwftp_send_msg(s, s->pass, strlen(s->pass)); + lwftp_send_msg(s, PTRNLEN("\n")); + s->control_state = LWFTP_PASS_SENT; + } else { + s->control_state = LWFTP_QUIT; + } + } + break; + case LWFTP_PASS_SENT: + if (response>0) { + if (response==230) { + s->control_state = LWFTP_LOGGED; + LWIP_DEBUGF(LWFTP_STATE, ("lwftp: now logged in\n")); + if (s->done_fn) { + s->done_fn(s->handle, LWFTP_RESULT_LOGGED); + } + } else { + s->control_state = LWFTP_QUIT; + } + } + break; + case LWFTP_TYPE_SENT: + if (response>0) { + if (response==200) { + lwftp_send_msg(s, PTRNLEN("PASV\n")); + s->control_state = LWFTP_PASV_SENT; + } else { + s->control_state = LWFTP_QUIT; + } + } + break; + case LWFTP_PASV_SENT: + if (response>0) { + if (response==227) { + lwftp_data_open(s,p); + switch (s->target_state) { + case LWFTP_STOR_SENT: + lwftp_send_msg(s, PTRNLEN("STOR ")); + break; + case LWFTP_RETR_SENT: + lwftp_send_msg(s, PTRNLEN("RETR ")); + break; + default: + LOGE(TAG, "Unexpected internal state"); + s->target_state = LWFTP_QUIT; + } + lwftp_send_msg(s, s->remote_path, strlen(s->remote_path)); + lwftp_send_msg(s, PTRNLEN("\n")); + s->control_state = s->target_state; + } else { + s->control_state = LWFTP_QUIT; + } + } + break; + case LWFTP_RETR_SENT: + if (response>0) { + if (response==150) { + s->control_state = LWFTP_XFERING; + } else if (response==550) { + s->control_state = LWFTP_DATAEND; + result = LWFTP_RESULT_ERR_FILENAME; + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp: Failed to open file '%s'\n", s->remote_path)); + } + else { + s->control_state = LWFTP_DATAEND; + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 150, received %d\n",response)); + } + } + break; + case LWFTP_STOR_SENT: + if (response>0) { + if (response==150) { + s->control_state = LWFTP_XFERING; + lwftp_data_sent(s,NULL,0); + } else { + s->control_state = LWFTP_DATAEND; + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 150, received %d\n",response)); + } + } + break; + case LWFTP_XFERING: + if (response>0) { + if (response==226) { + result = LWFTP_RESULT_OK; + } else { + result = LWFTP_RESULT_ERR_CLOSED; + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 226, received %d\n",response)); + } + s->control_state = LWFTP_DATAEND; + } + break; + case LWFTP_DATAEND: + LOGE(TAG, "forced end of data session"); + break; + case LWFTP_QUIT_SENT: + if (response>0) { + if (response==221) { + result = LWFTP_RESULT_OK; + } else { + result = LWFTP_RESULT_ERR_UNKNOWN; + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 221, received %d\n",response)); + } + s->control_state = LWFTP_CLOSING; + } + break; + default: + LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:unhandled state (%d)\n",s->control_state)); + } + + // Free receiving pbuf if any + if (p) { + pbuf_free(p); + } + + // Handle second step in state machine + switch ( s->control_state ) { + case LWFTP_DATAEND: + lwftp_data_close(s, result); + s->control_state = LWFTP_LOGGED; + break; + case LWFTP_QUIT: + lwftp_send_msg(s, PTRNLEN("QUIT\n")); + tcp_output(s->control_pcb); + s->control_state = LWFTP_QUIT_SENT; + break; + case LWFTP_CLOSING: + // this function frees s, no use of s is allowed after + lwftp_control_close(s, result); + default:; + } +} + +/** Start a RETR data session + * @param pointer to lwftp session + */ +static void lwftp_start_RETR(void *arg) +{ + lwftp_session_t *s = (lwftp_session_t*)arg; + + if ( s->control_state == LWFTP_LOGGED ) { + lwftp_send_msg(s, PTRNLEN("TYPE I\n")); + s->control_state = LWFTP_TYPE_SENT; + s->target_state = LWFTP_RETR_SENT; + } else { + LOGE(TAG, "Unexpected condition"); + if (s->done_fn) s->done_fn(s->handle, LWFTP_RESULT_ERR_INTERNAL); + } +} + +/** Start a STOR data session + * @param pointer to lwftp session + */ +static void lwftp_start_STOR(void *arg) +{ + lwftp_session_t *s = (lwftp_session_t*)arg; + + if ( s->control_state == LWFTP_LOGGED ) { + lwftp_send_msg(s, PTRNLEN("TYPE I\n")); + s->control_state = LWFTP_TYPE_SENT; + s->target_state = LWFTP_STOR_SENT; + } else { + LOGE(TAG, "Unexpected condition"); + if (s->done_fn) s->done_fn(s->handle, LWFTP_RESULT_ERR_INTERNAL); + } +} + +/** Send QUIT to terminate control session + * @param pointer to lwftp session + */ +static void lwftp_send_QUIT(void *arg) +{ + lwftp_session_t *s = (lwftp_session_t*)arg; + + if (s->control_pcb) { + lwftp_send_msg(s, PTRNLEN("QUIT\n")); + tcp_output(s->control_pcb); + s->control_state = LWFTP_QUIT_SENT; + } +} + +/** Handle control connection incoming data + * @param pointer to lwftp session data + * @param pointer to PCB + * @param pointer to incoming pbuf + * @param state of incoming process + */ +static err_t lwftp_control_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) +{ + lwftp_session_t *s = (lwftp_session_t*)arg; + + if ( err == ERR_OK ) { + if (p) { + tcp_recved(tpcb, p->tot_len); + lwftp_control_process(s, tpcb, p); + } else { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:connection closed by remote host\n")); + lwftp_control_close(s, LWFTP_RESULT_ERR_CLOSED); + } + } else { + LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:failed to receive (%s)\n",lwip_strerr(err))); + lwftp_control_close(s, LWFTP_RESULT_ERR_UNKNOWN); + } + return err; +} + +/** Handle control connection acknowledge of sent data + * @param pointer to lwftp session data + * @param pointer to PCB + * @param number of bytes sent + */ +static err_t lwftp_control_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) +{ + LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:successfully sent %d bytes\n",len)); + return ERR_OK; +} + +/** Handle control connection error + * @param pointer to lwftp session data + * @param state of connection + */ +static void lwftp_control_err(void *arg, err_t err) +{ + LWIP_UNUSED_ARG(err); + if (arg != NULL) { + lwftp_session_t *s = (lwftp_session_t*)arg; + int result; + if( s->control_state == LWFTP_CLOSED ) { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:failed to connect to server (%s)\n",lwip_strerr(err))); + result = LWFTP_RESULT_ERR_CONNECT; + } else { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:connection closed by remote host\n")); + result = LWFTP_RESULT_ERR_CLOSED; + } + s->control_pcb = NULL; // No need to de-allocate PCB + lwftp_control_close(s, result); + } +} + + +/** Process newly connected PCB + * @param pointer to lwftp session data + * @param pointer to PCB + * @param state of connection + */ +static err_t lwftp_control_connected(void *arg, struct tcp_pcb *tpcb, err_t err) +{ + lwftp_session_t *s = (lwftp_session_t*)arg; + + if ( err == ERR_OK ) { + LWIP_DEBUGF(LWFTP_STATE, ("lwftp:connected to server\n")); + s->control_state = LWFTP_CONNECTED; + } else { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:err in control_connected (%s)\n",lwip_strerr(err))); + } + return err; +} + + +/** Open a control session + * @param Session structure + */ +err_t lwftp_connect(lwftp_session_t *s) +{ + err_t error; + enum lwftp_results retval = LWFTP_RESULT_ERR_UNKNOWN; + + // Check user supplied data + if ( (s->control_state!=LWFTP_CLOSED) || + s->control_pcb || + s->data_pcb || + !s->user || + !s->pass ) + { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:invalid control session\n")); + retval = LWFTP_RESULT_ERR_ARGUMENT; + goto exit; + } + // Get sessions pcb + s->control_pcb = tcp_new(); + if (!s->control_pcb) { + LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc control_pcb (low memory?)\n")); + retval = LWFTP_RESULT_ERR_MEMORY; + goto exit; + } + // Open control session + tcp_arg(s->control_pcb, s); + tcp_err(s->control_pcb, lwftp_control_err); + tcp_recv(s->control_pcb, lwftp_control_recv); + tcp_sent(s->control_pcb, lwftp_control_sent); + error = tcp_connect(s->control_pcb, &s->server_ip, s->server_port, lwftp_control_connected); + if ( error == ERR_OK ) { + retval = LWFTP_RESULT_INPROGRESS; + goto exit; + } + + // Release pcbs in case of failure + LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot connect control_pcb (%s)\n", lwip_strerr(error))); + lwftp_control_close(s, -1); + +exit: + if (s->done_fn) s->done_fn(s->handle, retval); + return retval; +} + + +/** Retrieve data from a remote file + * @param Session structure + */ +err_t lwftp_retrieve(lwftp_session_t *s) +{ + err_t error; + enum lwftp_results retval = LWFTP_RESULT_ERR_UNKNOWN; + + // Check user supplied data + if ( (s->control_state!=LWFTP_LOGGED) || + !s->remote_path || + s->data_pcb ) + { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:invalid session data\n")); + retval = LWFTP_RESULT_ERR_ARGUMENT; + goto exit; + } + // Get data pcb + s->data_pcb = tcp_new(); + if (!s->data_pcb) { + LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc data_pcb (low memory?)\n")); + retval = LWFTP_RESULT_ERR_MEMORY; + goto exit; + } + // Initiate transfer + error = tcpip_callback(lwftp_start_RETR, s); + if ( error == ERR_OK ) { + retval = LWFTP_RESULT_INPROGRESS; + } else { + LOGE(TAG, "cannot start RETR (%s)",lwip_strerr(error)); + retval = LWFTP_RESULT_ERR_INTERNAL; + } + +exit: + if (s->done_fn) s->done_fn(s->handle, retval); + return retval; +} + + +/** Store data to a remote file + * @param Session structure + */ +err_t lwftp_store(lwftp_session_t *s) +{ + err_t error; + enum lwftp_results retval = LWFTP_RESULT_ERR_UNKNOWN; + + // Check user supplied data + if ( (s->control_state!=LWFTP_LOGGED) || + !s->remote_path || + s->data_pcb ) + { + LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:invalid session data\n")); + retval = LWFTP_RESULT_ERR_ARGUMENT; + goto exit; + } + // Get data pcb + s->data_pcb = tcp_new(); + if (!s->data_pcb) { + LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc data_pcb (low memory?)\n")); + retval = LWFTP_RESULT_ERR_MEMORY; + goto exit; + } + // Initiate transfer + error = tcpip_callback(lwftp_start_STOR, s); + if ( error == ERR_OK ) { + retval = LWFTP_RESULT_INPROGRESS; + } else { + LOGE(TAG, "cannot start STOR (%s)",lwip_strerr(error)); + retval = LWFTP_RESULT_ERR_INTERNAL; + } + +exit: + if (s->done_fn) s->done_fn(s->handle, retval); + return retval; +} + + +/** Terminate FTP session + * @param Session structure + */ +void lwftp_close(lwftp_session_t *s) +{ + err_t error; + + // Nothing to do when already closed + if ( s->control_state == LWFTP_CLOSED ) return; + + // Initiate transfer + error = tcpip_callback(lwftp_send_QUIT, s); + if ( error != ERR_OK ) { + // This is a critical error, try to close anyway + // polling process may save us + LOGE(TAG, "cannot request for close"); + s->control_state = LWFTP_QUIT; + } +} diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/CMakeLists.txt b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/CMakeLists.txt index 4fed1c5..b68faf0 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/CMakeLists.txt +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/CMakeLists.txt @@ -8,6 +8,8 @@ include_directories( ${SDK_ROOT}/lib/freertos/include ${SDK_ROOT}/lib/freertos/conf ${SDK_ROOT}/lib/freertos/portable + ${SDK_ROOT}/lib/hal/include + ${SDK_ROOT}/third_party/lwip/src/include ) # Add wolfSSL library source files, to be compiled as SHARED library diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/chacha20.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/chacha20.h new file mode 100644 index 0000000..2ae5e6e --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/chacha20.h @@ -0,0 +1,226 @@ +/** + * \file chacha20.h + * + * \brief This file contains ChaCha20 definitions and functions. + * + * ChaCha20 is a stream cipher that can encrypt and decrypt + * information. ChaCha was created by Daniel Bernstein as a variant of + * its Salsa cipher https://cr.yp.to/chacha/chacha-20080128.pdf + * ChaCha20 is the variant with 20 rounds, that was also standardized + * in RFC 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CHACHA20_H +#define MBEDTLS_CHACHA20_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA -0x0051 /**< Invalid input parameter(s). */ + +/* MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE is deprecated and should not be + * used. */ +#define MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE -0x0053 /**< Feature not available. For example, s part of the API is not implemented. */ + +/* MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED -0x0055 /**< Chacha20 hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_CHACHA20_ALT) + +typedef struct mbedtls_chacha20_context +{ + uint32_t state[16]; /*! The state (before round operations). */ + uint8_t keystream8[64]; /*! Leftover keystream bytes. */ + size_t keystream_bytes_used; /*! Number of keystream bytes already used. */ +} +mbedtls_chacha20_context; + +#else /* MBEDTLS_CHACHA20_ALT */ +#include "chacha20_alt.h" +#endif /* MBEDTLS_CHACHA20_ALT */ + +/** + * \brief This function initializes the specified ChaCha20 context. + * + * It must be the first API called before using + * the context. + * + * It is usually followed by calls to + * \c mbedtls_chacha20_setkey() and + * \c mbedtls_chacha20_starts(), then one or more calls to + * to \c mbedtls_chacha20_update(), and finally to + * \c mbedtls_chacha20_free(). + * + * \param ctx The ChaCha20 context to initialize. + * This must not be \c NULL. + */ +void mbedtls_chacha20_init( mbedtls_chacha20_context *ctx ); + +/** + * \brief This function releases and clears the specified + * ChaCha20 context. + * + * \param ctx The ChaCha20 context to clear. This may be \c NULL, + * in which case this function is a no-op. If it is not + * \c NULL, it must point to an initialized context. + * + */ +void mbedtls_chacha20_free( mbedtls_chacha20_context *ctx ); + +/** + * \brief This function sets the encryption/decryption key. + * + * \note After using this function, you must also call + * \c mbedtls_chacha20_starts() to set a nonce before you + * start encrypting/decrypting data with + * \c mbedtls_chacha_update(). + * + * \param ctx The ChaCha20 context to which the key should be bound. + * It must be initialized. + * \param key The encryption/decryption key. This must be \c 32 Bytes + * in length. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or key is NULL. + */ +int mbedtls_chacha20_setkey( mbedtls_chacha20_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This function sets the nonce and initial counter value. + * + * \note A ChaCha20 context can be re-used with the same key by + * calling this function to change the nonce. + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality guarantees for the + * messages encrypted with the same nonce and key. + * + * \param ctx The ChaCha20 context to which the nonce should be bound. + * It must be initialized and bound to a key. + * \param nonce The nonce. This must be \c 12 Bytes in size. + * \param counter The initial counter value. This is usually \c 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or nonce is + * NULL. + */ +int mbedtls_chacha20_starts( mbedtls_chacha20_context* ctx, + const unsigned char nonce[12], + uint32_t counter ); + +/** + * \brief This function encrypts or decrypts data. + * + * Since ChaCha20 is a stream cipher, the same operation is + * used for encrypting and decrypting data. + * + * \note The \p input and \p output pointers must either be equal or + * point to non-overlapping buffers. + * + * \note \c mbedtls_chacha20_setkey() and + * \c mbedtls_chacha20_starts() must be called at least once + * to setup the context before this function can be called. + * + * \note This function can be called multiple times in a row in + * order to encrypt of decrypt data piecewise with the same + * key and nonce. + * + * \param ctx The ChaCha20 context to use for encryption or decryption. + * It must be initialized and bound to a key and nonce. + * \param size The length of the input data in Bytes. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `size == 0`. + * \param output The buffer holding the output data. + * This must be able to hold \p size Bytes. + * This pointer can be \c NULL if `size == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chacha20_update( mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function encrypts or decrypts data with ChaCha20 and + * the given key and nonce. + * + * Since ChaCha20 is a stream cipher, the same operation is + * used for encrypting and decrypting data. + * + * \warning You must never use the same (key, nonce) pair more than + * once. This would void any confidentiality guarantees for + * the messages encrypted with the same nonce and key. + * + * \note The \p input and \p output pointers must either be equal or + * point to non-overlapping buffers. + * + * \param key The encryption/decryption key. + * This must be \c 32 Bytes in length. + * \param nonce The nonce. This must be \c 12 Bytes in size. + * \param counter The initial counter value. This is usually \c 0. + * \param size The length of the input data in Bytes. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `size == 0`. + * \param output The buffer holding the output data. + * This must be able to hold \p size Bytes. + * This pointer can be \c NULL if `size == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chacha20_crypt( const unsigned char key[32], + const unsigned char nonce[12], + uint32_t counter, + size_t size, + const unsigned char* input, + unsigned char* output ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The ChaCha20 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_chacha20_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CHACHA20_H */ diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/chachapoly.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/chachapoly.h new file mode 100644 index 0000000..49e615d --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/chachapoly.h @@ -0,0 +1,358 @@ +/** + * \file chachapoly.h + * + * \brief This file contains the AEAD-ChaCha20-Poly1305 definitions and + * functions. + * + * ChaCha20-Poly1305 is an algorithm for Authenticated Encryption + * with Associated Data (AEAD) that can be used to encrypt and + * authenticate data. It is based on ChaCha20 and Poly1305 by Daniel + * Bernstein and was standardized in RFC 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CHACHAPOLY_H +#define MBEDTLS_CHACHAPOLY_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/* for shared error codes */ +#include "poly1305.h" + +#define MBEDTLS_ERR_CHACHAPOLY_BAD_STATE -0x0054 /**< The requested operation is not permitted in the current state. */ +#define MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED -0x0056 /**< Authenticated decryption failed: data was not authentic. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + MBEDTLS_CHACHAPOLY_ENCRYPT, /**< The mode value for performing encryption. */ + MBEDTLS_CHACHAPOLY_DECRYPT /**< The mode value for performing decryption. */ +} +mbedtls_chachapoly_mode_t; + +#if !defined(MBEDTLS_CHACHAPOLY_ALT) + +#include "chacha20.h" + +typedef struct mbedtls_chachapoly_context +{ + mbedtls_chacha20_context chacha20_ctx; /**< The ChaCha20 context. */ + mbedtls_poly1305_context poly1305_ctx; /**< The Poly1305 context. */ + uint64_t aad_len; /**< The length (bytes) of the Additional Authenticated Data. */ + uint64_t ciphertext_len; /**< The length (bytes) of the ciphertext. */ + int state; /**< The current state of the context. */ + mbedtls_chachapoly_mode_t mode; /**< Cipher mode (encrypt or decrypt). */ +} +mbedtls_chachapoly_context; + +#else /* !MBEDTLS_CHACHAPOLY_ALT */ +#include "chachapoly_alt.h" +#endif /* !MBEDTLS_CHACHAPOLY_ALT */ + +/** + * \brief This function initializes the specified ChaCha20-Poly1305 context. + * + * It must be the first API called before using + * the context. It must be followed by a call to + * \c mbedtls_chachapoly_setkey() before any operation can be + * done, and to \c mbedtls_chachapoly_free() once all + * operations with that context have been finished. + * + * In order to encrypt or decrypt full messages at once, for + * each message you should make a single call to + * \c mbedtls_chachapoly_crypt_and_tag() or + * \c mbedtls_chachapoly_auth_decrypt(). + * + * In order to encrypt messages piecewise, for each + * message you should make a call to + * \c mbedtls_chachapoly_starts(), then 0 or more calls to + * \c mbedtls_chachapoly_update_aad(), then 0 or more calls to + * \c mbedtls_chachapoly_update(), then one call to + * \c mbedtls_chachapoly_finish(). + * + * \warning Decryption with the piecewise API is discouraged! Always + * use \c mbedtls_chachapoly_auth_decrypt() when possible! + * + * If however this is not possible because the data is too + * large to fit in memory, you need to: + * + * - call \c mbedtls_chachapoly_starts() and (if needed) + * \c mbedtls_chachapoly_update_aad() as above, + * - call \c mbedtls_chachapoly_update() multiple times and + * ensure its output (the plaintext) is NOT used in any other + * way than placing it in temporary storage at this point, + * - call \c mbedtls_chachapoly_finish() to compute the + * authentication tag and compared it in constant time to the + * tag received with the ciphertext. + * + * If the tags are not equal, you must immediately discard + * all previous outputs of \c mbedtls_chachapoly_update(), + * otherwise you can now safely use the plaintext. + * + * \param ctx The ChachaPoly context to initialize. Must not be \c NULL. + */ +void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx ); + +/** + * \brief This function releases and clears the specified + * ChaCha20-Poly1305 context. + * + * \param ctx The ChachaPoly context to clear. This may be \c NULL, in which + * case this function is a no-op. + */ +void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx ); + +/** + * \brief This function sets the ChaCha20-Poly1305 + * symmetric encryption key. + * + * \param ctx The ChaCha20-Poly1305 context to which the key should be + * bound. This must be initialized. + * \param key The \c 256 Bit (\c 32 Bytes) key. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This function starts a ChaCha20-Poly1305 encryption or + * decryption operation. + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality and authenticity + * guarantees for the messages encrypted with the same nonce + * and key. + * + * \note If the context is being used for AAD only (no data to + * encrypt or decrypt) then \p mode can be set to any value. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context. This must be initialized + * and bound to a key. + * \param nonce The nonce/IV to use for the message. + * This must be a redable buffer of length \c 12 Bytes. + * \param mode The operation to perform: #MBEDTLS_CHACHAPOLY_ENCRYPT or + * #MBEDTLS_CHACHAPOLY_DECRYPT (discouraged, see warning). + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx, + const unsigned char nonce[12], + mbedtls_chachapoly_mode_t mode ); + +/** + * \brief This function feeds additional data to be authenticated + * into an ongoing ChaCha20-Poly1305 operation. + * + * The Additional Authenticated Data (AAD), also called + * Associated Data (AD) is only authenticated but not + * encrypted nor included in the encrypted output. It is + * usually transmitted separately from the ciphertext or + * computed locally by each party. + * + * \note This function is called before data is encrypted/decrypted. + * I.e. call this function to process the AAD before calling + * \c mbedtls_chachapoly_update(). + * + * You may call this function multiple times to process + * an arbitrary amount of AAD. It is permitted to call + * this function 0 times, if no AAD is used. + * + * This function cannot be called any more if data has + * been processed by \c mbedtls_chachapoly_update(), + * or if the context has been finished. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context. This must be initialized + * and bound to a key. + * \param aad_len The length in Bytes of the AAD. The length has no + * restrictions. + * \param aad Buffer containing the AAD. + * This pointer can be \c NULL if `aad_len == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA + * if \p ctx or \p aad are NULL. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operations has not been started or has been + * finished, or if the AAD has been finished. + */ +int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx, + const unsigned char *aad, + size_t aad_len ); + +/** + * \brief Thus function feeds data to be encrypted or decrypted + * into an on-going ChaCha20-Poly1305 + * operation. + * + * The direction (encryption or decryption) depends on the + * mode that was given when calling + * \c mbedtls_chachapoly_starts(). + * + * You may call this function multiple times to process + * an arbitrary amount of data. It is permitted to call + * this function 0 times, if no data is to be encrypted + * or decrypted. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context to use. This must be initialized. + * \param len The length (in bytes) of the data to encrypt or decrypt. + * \param input The buffer containing the data to encrypt or decrypt. + * This pointer can be \c NULL if `len == 0`. + * \param output The buffer to where the encrypted or decrypted data is + * written. This must be able to hold \p len bytes. + * This pointer can be \c NULL if `len == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operation has not been started or has been + * finished. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx, + size_t len, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function finished the ChaCha20-Poly1305 operation and + * generates the MAC (authentication tag). + * + * \param ctx The ChaCha20-Poly1305 context to use. This must be initialized. + * \param mac The buffer to where the 128-bit (16 bytes) MAC is written. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operation has not been started or has been + * finished. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, + unsigned char mac[16] ); + +/** + * \brief This function performs a complete ChaCha20-Poly1305 + * authenticated encryption with the previously-set key. + * + * \note Before using this function, you must set the key with + * \c mbedtls_chachapoly_setkey(). + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality and authenticity + * guarantees for the messages encrypted with the same nonce + * and key. + * + * \param ctx The ChaCha20-Poly1305 context to use (holds the key). + * This must be initialized. + * \param length The length (in bytes) of the data to encrypt or decrypt. + * \param nonce The 96-bit (12 bytes) nonce/IV to use. + * \param aad The buffer containing the additional authenticated + * data (AAD). This pointer can be \c NULL if `aad_len == 0`. + * \param aad_len The length (in bytes) of the AAD data to process. + * \param input The buffer containing the data to encrypt or decrypt. + * This pointer can be \c NULL if `ilen == 0`. + * \param output The buffer to where the encrypted or decrypted data + * is written. This pointer can be \c NULL if `ilen == 0`. + * \param tag The buffer to where the computed 128-bit (16 bytes) MAC + * is written. This must not be \c NULL. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ); + +/** + * \brief This function performs a complete ChaCha20-Poly1305 + * authenticated decryption with the previously-set key. + * + * \note Before using this function, you must set the key with + * \c mbedtls_chachapoly_setkey(). + * + * \param ctx The ChaCha20-Poly1305 context to use (holds the key). + * \param length The length (in Bytes) of the data to decrypt. + * \param nonce The \c 96 Bit (\c 12 bytes) nonce/IV to use. + * \param aad The buffer containing the additional authenticated data (AAD). + * This pointer can be \c NULL if `aad_len == 0`. + * \param aad_len The length (in bytes) of the AAD data to process. + * \param tag The buffer holding the authentication tag. + * This must be a readable buffer of length \c 16 Bytes. + * \param input The buffer containing the data to decrypt. + * This pointer can be \c NULL if `ilen == 0`. + * \param output The buffer to where the decrypted data is written. + * This pointer can be \c NULL if `ilen == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED + * if the data was not authentic. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char tag[16], + const unsigned char *input, + unsigned char *output ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The ChaCha20-Poly1305 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_chachapoly_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CHACHAPOLY_H */ diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/config.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/config.h index 1ba3290..d1a0ee3 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/config.h +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/config.h @@ -60,7 +60,7 @@ */ #define MBEDTLS_HAVE_ASM - /** +/** * \def MBEDTLS_NO_UDBL_DIVISION * * The platform lacks support for double-width integer division (64-bit @@ -132,7 +132,7 @@ * * Comment if your system does not support time functions */ -//#define MBEDTLS_HAVE_TIME +#define MBEDTLS_HAVE_TIME /** * \def MBEDTLS_HAVE_TIME_DATE @@ -153,7 +153,7 @@ * mbedtls_platform_gmtime_r() at compile-time by using the macro * MBEDTLS_PLATFORM_GMTIME_R_ALT. */ -//#define MBEDTLS_HAVE_TIME_DATE +#define MBEDTLS_HAVE_TIME_DATE /** * \def MBEDTLS_PLATFORM_MEMORY @@ -346,30 +346,30 @@ * digests and ciphers instead. * */ - //#define MBEDTLS_AES_ALT - //#define MBEDTLS_ARC4_ALT - //#define MBEDTLS_ARIA_ALT - //#define MBEDTLS_BLOWFISH_ALT - //#define MBEDTLS_CAMELLIA_ALT - //#define MBEDTLS_CCM_ALT - //#define MBEDTLS_CHACHA20_ALT - //#define MBEDTLS_CHACHAPOLY_ALT - //#define MBEDTLS_CMAC_ALT - //#define MBEDTLS_DES_ALT - //#define MBEDTLS_DHM_ALT - //#define MBEDTLS_ECJPAKE_ALT - //#define MBEDTLS_GCM_ALT - //#define MBEDTLS_NIST_KW_ALT - //#define MBEDTLS_MD2_ALT - //#define MBEDTLS_MD4_ALT - //#define MBEDTLS_MD5_ALT - //#define MBEDTLS_POLY1305_ALT - //#define MBEDTLS_RIPEMD160_ALT - //#define MBEDTLS_RSA_ALT - //#define MBEDTLS_SHA1_ALT - //#define MBEDTLS_SHA256_ALT - //#define MBEDTLS_SHA512_ALT - //#define MBEDTLS_XTEA_ALT +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_ARIA_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_CCM_ALT +//#define MBEDTLS_CHACHA20_ALT +//#define MBEDTLS_CHACHAPOLY_ALT +//#define MBEDTLS_CMAC_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_DHM_ALT +//#define MBEDTLS_ECJPAKE_ALT +//#define MBEDTLS_GCM_ALT +//#define MBEDTLS_NIST_KW_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_POLY1305_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_RSA_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_ALT +//#define MBEDTLS_XTEA_ALT /* * When replacing the elliptic curve module, pleace consider, that it is @@ -540,7 +540,7 @@ */ #define MBEDTLS_AES_ROM_TABLES - /** +/** * \def MBEDTLS_AES_FEWER_TABLES * * Use less ROM/RAM for AES tables. @@ -560,7 +560,7 @@ * This option is independent of \c MBEDTLS_AES_ROM_TABLES. * */ - //#define MBEDTLS_AES_FEWER_TABLES +//#define MBEDTLS_AES_FEWER_TABLES /** * \def MBEDTLS_CAMELLIA_SMALL_MEMORY @@ -1115,7 +1115,7 @@ * This option is only useful if both MBEDTLS_SHA256_C and * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. */ -#define MBEDTLS_ENTROPY_FORCE_SHA256 +//#define MBEDTLS_ENTROPY_FORCE_SHA256 /** * \def MBEDTLS_ENTROPY_NV_SEED @@ -1611,7 +1611,7 @@ * * Uncomment this to allow your own alternate threading implementation. */ -#define MBEDTLS_THREADING_ALT +//#define MBEDTLS_THREADING_ALT /** * \def MBEDTLS_THREADING_PTHREAD @@ -2814,7 +2814,7 @@ * * Enable this layer to allow use of mutexes within mbed TLS */ -#define MBEDTLS_THREADING_C +//#define MBEDTLS_THREADING_C /** * \def MBEDTLS_TIMING_C diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/config.h.orig b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/config.h.orig new file mode 100644 index 0000000..1ba3290 --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/config.h.orig @@ -0,0 +1,3273 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/aria.c + * library/timing.c + * include/mbedtls/bn_mul.h + * + * Required by: + * MBEDTLS_AESNI_C + * MBEDTLS_PADLOCK_C + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + + /** + * \def MBEDTLS_NO_UDBL_DIVISION + * + * The platform lacks support for double-width integer division (64-bit + * division on a 32-bit platform, 128-bit division on a 64-bit platform). + * + * Used in: + * include/mbedtls/bignum.h + * library/bignum.c + * + * The bignum code uses double-width division to speed up some operations. + * Double-width division is often implemented in software that needs to + * be linked with the program. The presence of a double-width integer + * type is usually detected automatically through preprocessor macros, + * but the automatic detection cannot know whether the code needs to + * and can be linked with an implementation of division for that type. + * By default division is assumed to be usable if the type is present. + * Uncomment this option to prevent the use of double-width division. + * + * Note that division for the native integer type is always required. + * Furthermore, a 64-bit type is always required even on a 32-bit + * platform, but it need not support multiplication or division. In some + * cases it is also desirable to disable some double-width operations. For + * example, if double-width division is implemented in software, disabling + * it can reduce code size in some embedded targets. + */ +//#define MBEDTLS_NO_UDBL_DIVISION + +/** + * \def MBEDTLS_NO_64BIT_MULTIPLICATION + * + * The platform lacks support for 32x32 -> 64-bit multiplication. + * + * Used in: + * library/poly1305.c + * + * Some parts of the library may use multiplication of two unsigned 32-bit + * operands with a 64-bit result in order to speed up computations. On some + * platforms, this is not available in hardware and has to be implemented in + * software, usually in a library provided by the toolchain. + * + * Sometimes it is not desirable to have to link to that library. This option + * removes the dependency of that library on platforms that lack a hardware + * 64-bit multiplier by embedding a software implementation in Mbed TLS. + * + * Note that depending on the compiler, this may decrease performance compared + * to using the library function provided by the toolchain. + */ +//#define MBEDTLS_NO_64BIT_MULTIPLICATION + +/** + * \def MBEDTLS_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + */ +//#define MBEDTLS_HAVE_SSE2 + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * + * Comment if your system does not support time functions + */ +//#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_HAVE_TIME_DATE + * + * System has time.h, time(), and an implementation for + * mbedtls_platform_gmtime_r() (see below). + * The time needs to be correct (not necesarily very accurate, but at least + * the date should be correct). This is used to verify the validity period of + * X.509 certificates. + * + * Comment if your system does not have a correct clock. + * + * \note mbedtls_platform_gmtime_r() is an abstraction in platform_util.h that + * behaves similarly to the gmtime_r() function from the C standard. Refer to + * the documentation for mbedtls_platform_gmtime_r() for more information. + * + * \note It is possible to configure an implementation for + * mbedtls_platform_gmtime_r() at compile-time by using the macro + * MBEDTLS_PLATFORM_GMTIME_R_ALT. + */ +//#define MBEDTLS_HAVE_TIME_DATE + +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def MBEDTLS_PLATFORM_EXIT_ALT + * + * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the + * function in the platform abstraction layer. + * + * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will + * provide a function "mbedtls_platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require MBEDTLS_PLATFORM_C to be defined! + * + * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; + * it will be enabled automatically by check_config.h + * + * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as + * MBEDTLS_PLATFORM_XXX_MACRO! + * + * Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_TIME_ALT +//#define MBEDTLS_PLATFORM_FPRINTF_ALT +//#define MBEDTLS_PLATFORM_PRINTF_ALT +//#define MBEDTLS_PLATFORM_SNPRINTF_ALT +//#define MBEDTLS_PLATFORM_NV_SEED_ALT +//#define MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions so that they generate a warning if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * This only works with GCC and Clang. With other compilers, you may want to + * use MBEDTLS_DEPRECATED_REMOVED + * + * Uncomment to get warnings on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions so that they generate an error if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * Uncomment to get errors on using deprecated functions. + */ +#define MBEDTLS_DEPRECATED_REMOVED + +/** + * \def MBEDTLS_CHECK_PARAMS + * + * This configuration option controls whether the library validates more of + * the parameters passed to it. + * + * When this flag is not defined, the library only attempts to validate an + * input parameter if: (1) they may come from the outside world (such as the + * network, the filesystem, etc.) or (2) not validating them could result in + * internal memory errors such as overflowing a buffer controlled by the + * library. On the other hand, it doesn't attempt to validate parameters whose + * values are fully controlled by the application (such as pointers). + * + * When this flag is defined, the library additionally attempts to validate + * parameters that are fully controlled by the application, and should always + * be valid if the application code is fully correct and trusted. + * + * For example, when a function accepts as input a pointer to a buffer that may + * contain untrusted data, and its documentation mentions that this pointer + * must not be NULL: + * - the pointer is checked to be non-NULL only if this option is enabled + * - the content of the buffer is always validated + * + * When this flag is defined, if a library function receives a parameter that + * is invalid, it will: + * - invoke the macro MBEDTLS_PARAM_FAILED() which by default expands to a + * call to the function mbedtls_param_failed() + * - immediately return (with a specific error code unless the function + * returns void and can't communicate an error). + * + * When defining this flag, you also need to: + * - either provide a definition of the function mbedtls_param_failed() in + * your application (see platform_util.h for its prototype) as the library + * calls that function, but does not provide a default definition for it, + * - or provide a different definition of the macro MBEDTLS_PARAM_FAILED() + * below if the above mechanism is not flexible enough to suit your needs. + * See the documentation of this macro later in this file. + * + * Uncomment to enable validation of application-controlled parameters. + */ +//#define MBEDTLS_CHECK_PARAMS + +/* \} name SECTION: System support */ + +/** + * \name SECTION: mbed TLS feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def MBEDTLS_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), + * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() + * + * Only works if you have MBEDTLS_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define MBEDTLS_TIMING_ALT + +/** + * \def MBEDTLS_AES_ALT + * + * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternate core implementation of a symmetric crypto, an arithmetic or hash + * module (e.g. platform specific assembly optimized implementations). Keep + * in mind that the function prototypes should remain the same. + * + * This replaces the whole module. If you only want to replace one of the + * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer + * provide the "struct mbedtls_aes_context" definition and omit the base + * function declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * module. + * + * \warning MD2, MD4, MD5, ARC4, DES and SHA-1 are considered weak and their + * use constitutes a security risk. If possible, we recommend + * avoiding dependencies on them, and considering stronger message + * digests and ciphers instead. + * + */ + //#define MBEDTLS_AES_ALT + //#define MBEDTLS_ARC4_ALT + //#define MBEDTLS_ARIA_ALT + //#define MBEDTLS_BLOWFISH_ALT + //#define MBEDTLS_CAMELLIA_ALT + //#define MBEDTLS_CCM_ALT + //#define MBEDTLS_CHACHA20_ALT + //#define MBEDTLS_CHACHAPOLY_ALT + //#define MBEDTLS_CMAC_ALT + //#define MBEDTLS_DES_ALT + //#define MBEDTLS_DHM_ALT + //#define MBEDTLS_ECJPAKE_ALT + //#define MBEDTLS_GCM_ALT + //#define MBEDTLS_NIST_KW_ALT + //#define MBEDTLS_MD2_ALT + //#define MBEDTLS_MD4_ALT + //#define MBEDTLS_MD5_ALT + //#define MBEDTLS_POLY1305_ALT + //#define MBEDTLS_RIPEMD160_ALT + //#define MBEDTLS_RSA_ALT + //#define MBEDTLS_SHA1_ALT + //#define MBEDTLS_SHA256_ALT + //#define MBEDTLS_SHA512_ALT + //#define MBEDTLS_XTEA_ALT + +/* + * When replacing the elliptic curve module, pleace consider, that it is + * implemented with two .c files: + * - ecp.c + * - ecp_curves.c + * You can replace them very much like all the other MBEDTLS__MODULE_NAME__ALT + * macros as described above. The only difference is that you have to make sure + * that you provide functionality for both .c files. + */ +//#define MBEDTLS_ECP_ALT + +/** + * \def MBEDTLS_MD2_PROCESS_ALT + * + * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you + * alternate core implementation of symmetric crypto or hash function. Keep in + * mind that function prototypes should remain the same. + * + * This replaces only one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will + * no longer provide the mbedtls_sha1_process() function, but it will still provide + * the other function (using your mbedtls_sha1_process() function) and the definition + * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible + * with this definition. + * + * \note Because of a signature change, the core AES encryption and decryption routines are + * currently named mbedtls_aes_internal_encrypt and mbedtls_aes_internal_decrypt, + * respectively. When setting up alternative implementations, these functions should + * be overriden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt + * must stay untouched. + * + * \note If you use the AES_xxx_ALT macros, then is is recommended to also set + * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES + * tables. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + * + * \warning MD2, MD4, MD5, DES and SHA-1 are considered weak and their use + * constitutes a security risk. If possible, we recommend avoiding + * dependencies on them, and considering stronger message digests + * and ciphers instead. + * + */ +//#define MBEDTLS_MD2_PROCESS_ALT +//#define MBEDTLS_MD4_PROCESS_ALT +//#define MBEDTLS_MD5_PROCESS_ALT +//#define MBEDTLS_RIPEMD160_PROCESS_ALT +//#define MBEDTLS_SHA1_PROCESS_ALT +//#define MBEDTLS_SHA256_PROCESS_ALT +//#define MBEDTLS_SHA512_PROCESS_ALT +//#define MBEDTLS_DES_SETKEY_ALT +//#define MBEDTLS_DES_CRYPT_ECB_ALT +//#define MBEDTLS_DES3_CRYPT_ECB_ALT +//#define MBEDTLS_AES_SETKEY_ENC_ALT +//#define MBEDTLS_AES_SETKEY_DEC_ALT +//#define MBEDTLS_AES_ENCRYPT_ALT +//#define MBEDTLS_AES_DECRYPT_ALT +//#define MBEDTLS_ECDH_GEN_PUBLIC_ALT +//#define MBEDTLS_ECDH_COMPUTE_SHARED_ALT +//#define MBEDTLS_ECDSA_VERIFY_ALT +//#define MBEDTLS_ECDSA_SIGN_ALT +//#define MBEDTLS_ECDSA_GENKEY_ALT + +/** + * \def MBEDTLS_ECP_INTERNAL_ALT + * + * Expose a part of the internal interface of the Elliptic Curve Point module. + * + * MBEDTLS_ECP__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternative core implementation of elliptic curve arithmetic. Keep in mind + * that function prototypes should remain the same. + * + * This partially replaces one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS_ECP_ALT flag. The original implementation + * is still present and it is used for group structures not supported by the + * alternative. + * + * Any of these options become available by defining MBEDTLS_ECP_INTERNAL_ALT + * and implementing the following functions: + * unsigned char mbedtls_internal_ecp_grp_capable( + * const mbedtls_ecp_group *grp ) + * int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) + * void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ) + * The mbedtls_internal_ecp_grp_capable function should return 1 if the + * replacement functions implement arithmetic for the given group and 0 + * otherwise. + * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_free are + * called before and after each point operation and provide an opportunity to + * implement optimized set up and tear down instructions. + * + * Example: In case you uncomment MBEDTLS_ECP_INTERNAL_ALT and + * MBEDTLS_ECP_DOUBLE_JAC_ALT, mbed TLS will still provide the ecp_double_jac + * function, but will use your mbedtls_internal_ecp_double_jac if the group is + * supported (your mbedtls_internal_ecp_grp_capable function returns 1 when + * receives it as an argument). If the group is not supported then the original + * implementation is used. The other functions and the definition of + * mbedtls_ecp_group and mbedtls_ecp_point will not change, so your + * implementation of mbedtls_internal_ecp_double_jac and + * mbedtls_internal_ecp_grp_capable must be compatible with this definition. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +/* Required for all the functions in this section */ +//#define MBEDTLS_ECP_INTERNAL_ALT +/* Support for Weierstrass curves with Jacobi representation */ +//#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT +//#define MBEDTLS_ECP_ADD_MIXED_ALT +//#define MBEDTLS_ECP_DOUBLE_JAC_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +/* Support for curves with Montgomery arithmetic */ +//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT +//#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT +//#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT + +/** + * \def MBEDTLS_TEST_NULL_ENTROPY + * + * Enables testing and use of mbed TLS without any configured entropy sources. + * This permits use of the library on platforms before an entropy source has + * been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the + * MBEDTLS_ENTROPY_NV_SEED switches). + * + * WARNING! This switch MUST be disabled in production builds, and is suitable + * only for development. + * Enabling the switch negates any security provided by the library. + * + * Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + */ +//#define MBEDTLS_TEST_NULL_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Uncomment this macro to let mbed TLS use your own implementation of a + * hardware entropy collector. + * + * Your function must be called \c mbedtls_hardware_poll(), have the same + * prototype as declared in entropy_poll.h, and accept NULL as first argument. + * + * Uncomment to use your own hardware entropy collector. + */ +//#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Use precomputed AES tables stored in ROM. + * + * Uncomment this macro to use precomputed AES tables stored in ROM. + * Comment this macro to generate AES tables in RAM at runtime. + * + * Tradeoff: Using precomputed ROM tables reduces RAM usage by ~8kb + * (or ~2kb if \c MBEDTLS_AES_FEWER_TABLES is used) and reduces the + * initialization time before the first AES operation can be performed. + * It comes at the cost of additional ~8kb ROM use (resp. ~2kb if \c + * MBEDTLS_AES_FEWER_TABLES below is used), and potentially degraded + * performance if ROM access is slower than RAM access. + * + * This option is independent of \c MBEDTLS_AES_FEWER_TABLES. + * + */ + #define MBEDTLS_AES_ROM_TABLES + + /** + * \def MBEDTLS_AES_FEWER_TABLES + * + * Use less ROM/RAM for AES tables. + * + * Uncommenting this macro omits 75% of the AES tables from + * ROM / RAM (depending on the value of \c MBEDTLS_AES_ROM_TABLES) + * by computing their values on the fly during operations + * (the tables are entry-wise rotations of one another). + * + * Tradeoff: Uncommenting this reduces the RAM / ROM footprint + * by ~6kb but at the cost of more arithmetic operations during + * runtime. Specifically, one has to compare 4 accesses within + * different tables to 4 accesses with additional arithmetic + * operations within the same table. The performance gain/loss + * depends on the system and memory details. + * + * This option is independent of \c MBEDTLS_AES_ROM_TABLES. + * + */ + //#define MBEDTLS_AES_FEWER_TABLES + +/** + * \def MBEDTLS_CAMELLIA_SMALL_MEMORY + * + * Use less ROM for the Camellia implementation (saves about 768 bytes). + * + * Uncomment this macro to use less memory for Camellia. + */ +//#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CFB + +/** + * \def MBEDTLS_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CTR + +/** + * \def MBEDTLS_CIPHER_MODE_OFB + * + * Enable Output Feedback mode (OFB) for symmetric ciphers. + */ +//#define MBEDTLS_CIPHER_MODE_OFB + +/** + * \def MBEDTLS_CIPHER_MODE_XTS + * + * Enable Xor-encrypt-xor with ciphertext stealing mode (XTS) for AES. + */ +//#define MBEDTLS_CIPHER_MODE_XTS + +/** + * \def MBEDTLS_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define MBEDTLS_CIPHER_NULL_CIPHER + +/** + * \def MBEDTLS_CIPHER_PADDING_PKCS7 + * + * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for + * specific padding modes in the cipher layer with cipher modes that support + * padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/** + * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS. + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. +*/ +//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +//#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +//#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +//#define MBEDTLS_ECP_DP_BP256R1_ENABLED +//#define MBEDTLS_ECP_DP_BP384R1_ENABLED +//#define MBEDTLS_ECP_DP_BP512R1_ENABLED +//#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +//#define MBEDTLS_ECP_DP_CURVE448_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_ECP_RESTARTABLE + * + * Enable "non-blocking" ECC operations that can return early and be resumed. + * + * This allows various functions to pause by returning + * #MBEDTLS_ERR_ECP_IN_PROGRESS (or, for functions in the SSL module, + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) and then be called later again in + * order to further progress and eventually complete their operation. This is + * controlled through mbedtls_ecp_set_max_ops() which limits the maximum + * number of ECC operations a function may perform before pausing; see + * mbedtls_ecp_set_max_ops() for more information. + * + * This is useful in non-threaded environments if you want to avoid blocking + * for too long on ECC (and, hence, X.509 or SSL/TLS) operations. + * + * Uncomment this macro to enable restartable ECC computations. + * + * \note This option only works with the default software implementation of + * elliptic curve functionality. It is incompatible with + * MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT and MBEDTLS_ECDSA_XXX_ALT. + */ +//#define MBEDTLS_ECP_RESTARTABLE + +/** + * \def MBEDTLS_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: MBEDTLS_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +//#define MBEDTLS_ECDSA_DETERMINISTIC + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + */ +//#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + * + * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Requires: MBEDTLS_ECJPAKE_C + * MBEDTLS_SHA256_C + * MBEDTLS_ECP_DP_SECP256R1_ENABLED + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + +/** + * \def MBEDTLS_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +//#define MBEDTLS_PK_PARSE_EC_EXTENDED + +/** + * \def MBEDTLS_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of mbedtls_strerror() in + * third party libraries easier when MBEDTLS_ERROR_C is disabled + * (no effect when MBEDTLS_ERROR_C is enabled). + * + * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're + * not using mbedtls_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * mbedtls_strerror() + */ +//#define MBEDTLS_ERROR_STRERROR_DUMMY + +/** + * \def MBEDTLS_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: MBEDTLS_BIGNUM_C + */ +#define MBEDTLS_GENPRIME + +/** + * \def MBEDTLS_FS_IO + * + * Enable functions that use the filesystem. + */ +//#define MBEDTLS_FS_IO + +/** + * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * mbedtls_timing_hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. + */ +//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + +/** + * \def MBEDTLS_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. + */ +#define MBEDTLS_NO_PLATFORM_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: MBEDTLS_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both MBEDTLS_SHA256_C and + * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. + */ +#define MBEDTLS_ENTROPY_FORCE_SHA256 + +/** + * \def MBEDTLS_ENTROPY_NV_SEED + * + * Enable the non-volatile (NV) seed file-based entropy source. + * (Also enables the NV seed read/write functions in the platform layer) + * + * This is crucial (if not required) on systems that do not have a + * cryptographic entropy source (in hardware or kernel) available. + * + * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C + * + * \note The read/write functions that are used by the entropy source are + * determined in the platform layer, and can be modified at runtime and/or + * compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used. + * + * \note If you use the default implementation functions that read a seedfile + * with regular fopen(), please make sure you make a seedfile with the + * proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at + * least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from + * and written to or you will get an entropy source error! The default + * implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE + * bytes from the file. + * + * \note The entropy collector will write to the seed file before entropy is + * given to an external source, to update it. + */ +//#define MBEDTLS_ENTROPY_NV_SEED + +/** + * \def MBEDTLS_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define MBEDTLS_MEMORY_DEBUG + +/** + * \def MBEDTLS_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define MBEDTLS_MEMORY_BACKTRACE + +/** + * \def MBEDTLS_PK_RSA_ALT_SUPPORT + * + * Support external private RSA keys (eg from a HSM) in the PK layer. + * + * Comment this macro to disable support for external private RSA keys. + */ +#define MBEDTLS_PK_RSA_ALT_SUPPORT + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +//#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem + * for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * + */ +//#define MBEDTLS_RSA_NO_CRT + +/** + * \def MBEDTLS_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +#define MBEDTLS_SELF_TEST + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +//#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, mbed TLS can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages + */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/** + * \def MBEDTLS_SSL_ASYNC_PRIVATE + * + * Enable asynchronous external private key operations in SSL. This allows + * you to configure an SSL connection to call an external cryptographic + * module to perform private key operations instead of performing the + * operation inside the library. + * + */ +//#define MBEDTLS_SSL_ASYNC_PRIVATE + +/** + * \def MBEDTLS_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * + */ +//#define MBEDTLS_SSL_DEBUG_ALL + +/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC + * + * Enable support for Encrypt-then-MAC, RFC 7366. + * + * This allows peers that both support it to use a more robust protection for + * ciphersuites using CBC, providing deep resistance against timing attacks + * on the padding or underlying cipher. + * + * This only affects CBC ciphersuites, and is useless if none is defined. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Encrypt-then-MAC + */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC + +/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET + * + * Enable support for Extended Master Secret, aka Session Hash + * (draft-ietf-tls-session-hash-02). + * + * This was introduced as "the proper fix" to the Triple Handshake familiy of + * attacks, but it is recommended to always use it (even if you disable + * renegotiation), since it actually fixes a more fundamental issue in the + * original SSL/TLS design, and has implications beyond Triple Handshake. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Extended Master Secret. + */ +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +/** + * \def MBEDTLS_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +//#define MBEDTLS_SSL_FALLBACK_SCSV + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. + */ +//#define MBEDTLS_SSL_HW_RECORD_ACCEL + +/** + * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +//#define MBEDTLS_SSL_CBC_RECORD_SPLITTING + +/** + * \def MBEDTLS_SSL_RENEGOTIATION + * + * Enable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Comment this to disable support for renegotiation. + * + * \note Even if this option is disabled, both client and server are aware + * of the Renegotiation Indication Extension (RFC 5746) used to + * prevent the SSL renegotiation attack (see RFC 5746 Sect. 1). + * (See \c mbedtls_ssl_conf_legacy_renegotiation for the + * configuration of this extension). + * + */ +//#define MBEDTLS_SSL_RENEGOTIATION + +/** + * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to enable support for SSLv2 Client Hello messages. + */ +//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +//#define MBEDTLS_SSL_PROTO_SSL3 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +//#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +//#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_PROTO_DTLS + * + * Enable support for DTLS (all available versions). + * + * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0, + * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_1 + * or MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for DTLS + */ +//#define MBEDTLS_SSL_PROTO_DTLS + +/** + * \def MBEDTLS_SSL_ALPN + * + * Enable support for RFC 7301 Application Layer Protocol Negotiation. + * + * Comment this macro to disable support for ALPN. + */ +#define MBEDTLS_SSL_ALPN + +/** + * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY + * + * Enable support for the anti-replay mechanism in DTLS. + * + * Requires: MBEDTLS_SSL_TLS_C + * MBEDTLS_SSL_PROTO_DTLS + * + * \warning Disabling this is often a security risk! + * See mbedtls_ssl_conf_dtls_anti_replay() for details. + * + * Comment this to disable anti-replay in DTLS. + */ +//#define MBEDTLS_SSL_DTLS_ANTI_REPLAY + +/** + * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Enable support for HelloVerifyRequest on DTLS servers. + * + * This feature is highly recommended to prevent DTLS servers being used as + * amplifiers in DoS attacks against other hosts. It should always be enabled + * unless you know for sure amplification cannot be a problem in the + * environment in which your server operates. + * + * \warning Disabling this can ba a security risk! (see above) + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Comment this to disable support for HelloVerifyRequest. + */ +//#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +//#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + +/** + * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT + * + * Enable support for a limit of records with bad MAC. + * + * See mbedtls_ssl_conf_dtls_badmac_limit(). + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +//#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/** + * \def MBEDTLS_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * Client-side, provides full support for session tickets (maintainance of a + * session store remains the responsibility of the application, though). + * Server-side, you also need to provide callbacks for writing and parsing + * tickets, including authenticated encryption and key management. Example + * callbacks are provided by MBEDTLS_SSL_TICKET_C. + * + * Comment this macro to disable support for SSL session tickets + */ +//#define MBEDTLS_SSL_SESSION_TICKETS + +/** + * \def MBEDTLS_SSL_EXPORT_KEYS + * + * Enable support for exporting key block and master secret. + * This is required for certain users of TLS, e.g. EAP-TLS. + * + * Comment this macro to disable support for key export + */ +//#define MBEDTLS_SSL_EXPORT_KEYS + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +//#define MBEDTLS_SSL_TRUNCATED_HMAC + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT + * + * Fallback to old (pre-2.7), non-conforming implementation of the truncated + * HMAC extension which also truncates the HMAC key. Note that this option is + * only meant for a transitory upgrade period and is likely to be removed in + * a future version of the library. + * + * \warning The old implementation is non-compliant and has a security weakness + * (2^80 brute force attack on the HMAC key used for a single, + * uninterrupted connection). This should only be enabled temporarily + * when (1) the use of truncated HMAC is essential in order to save + * bandwidth, and (2) the peer is an Mbed TLS stack that doesn't use + * the fixed implementation yet (pre-2.7). + * + * \deprecated This option is deprecated and will likely be removed in a + * future version of Mbed TLS. + * + * Uncomment to fallback to old, non-compliant truncated HMAC implementation. + * + * Requires: MBEDTLS_SSL_TRUNCATED_HMAC + */ +//#define MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT + +/** + * \def MBEDTLS_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +#define MBEDTLS_THREADING_ALT + +/** + * \def MBEDTLS_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define MBEDTLS_THREADING_PTHREAD + +/** + * \def MBEDTLS_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via mbedtls_version_check_feature(). + * + * Requires: MBEDTLS_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +#define MBEDTLS_VERSION_FEATURES + +/** + * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * \warning Depending on your PKI use, enabling this can be a security risk! + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def MBEDTLS_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define MBEDTLS_X509_CHECK_KEY_USAGE + +/** + * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +//#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * \deprecated This feature is deprecated and will be removed + * in the next major revision of the library. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +//#define MBEDTLS_ZLIB_SUPPORT +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +//#define MBEDTLS_AESNI_C + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/cipher.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. If possible, we recommend avoidng dependencies on + * it, and considering stronger ciphers instead. + * + */ +//#define MBEDTLS_ARC4_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/rsa_internal.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +//#define MBEDTLS_BLOWFISH_C + +/** + * \def MBEDTLS_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +//#define MBEDTLS_CAMELLIA_C + +/** + * \def MBEDTLS_ARIA_C + * + * Enable the ARIA block cipher. + * + * Module: library/aria.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * + * MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 + */ +//#define MBEDTLS_ARIA_C + +/** + * \def MBEDTLS_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +//#define MBEDTLS_CCM_C + +/** + * \def MBEDTLS_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +//#define MBEDTLS_CERTS_C + +/** + * \def MBEDTLS_CHACHA20_C + * + * Enable the ChaCha20 stream cipher. + * + * Module: library/chacha20.c + */ +//#define MBEDTLS_CHACHA20_C + +/** + * \def MBEDTLS_CHACHAPOLY_C + * + * Enable the ChaCha20-Poly1305 AEAD algorithm. + * + * Module: library/chachapoly.c + * + * This module requires: MBEDTLS_CHACHA20_C, MBEDTLS_POLY1305_C + */ +//#define MBEDTLS_CHACHAPOLY_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CMAC_C + * + * Enable the CMAC (Cipher-based Message Authentication Code) mode for block + * ciphers. + * + * Module: library/cmac.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C + * + */ +//#define MBEDTLS_CMAC_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-based random generator. + * The CTR_DRBG generator uses AES-256 by default. + * To use AES-128 instead, enable MBEDTLS_CTR_DRBG_USE_128_BIT_KEY below. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +//#define MBEDTLS_DEBUG_C + +/** + * \def MBEDTLS_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + */ +//#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +//#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECJPAKE_C + * + * Enable the elliptic curve J-PAKE library. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Module: library/ecjpake.c + * Caller: + * + * This module is used by the following key exchanges: + * ECJPAKE + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C + */ +//#define MBEDTLS_ECJPAKE_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables mbedtls_strerror(). + */ +//#define MBEDTLS_ERROR_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: MBEDTLS_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define MBEDTLS_HAVEGE_C + +/** + * \def MBEDTLS_HKDF_C + * + * Enable the HKDF algorithm (RFC 5869). + * + * Module: library/hkdf.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the Hashed Message Authentication Code + * (HMAC)-based key derivation function (HKDF). + */ +//#define MBEDTLS_HKDF_C + +/** + * \def MBEDTLS_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +//#define MBEDTLS_HMAC_DRBG_C + +/** + * \def MBEDTLS_NIST_KW_C + * + * Enable the Key Wrapping mode for 128-bit block ciphers, + * as defined in NIST SP 800-38F. Only KW and KWP modes + * are supported. At the moment, only AES is approved by NIST. + * + * Module: library/nist_kw.c + * + * Requires: MBEDTLS_AES_C and MBEDTLS_CIPHER_C + */ +//#define MBEDTLS_NIST_KW_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD2_C + * + * Enable the MD2 hash algorithm. + * + * Module: library/md2.c + * Caller: + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + * + * \warning MD2 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_MD2_C + +/** + * \def MBEDTLS_MD4_C + * + * Enable the MD4 hash algorithm. + * + * Module: library/md4.c + * Caller: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + * + * \warning MD4 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_MD4_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/md5.c + * Caller: library/md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS up to version 1.1, and for TLS 1.2 + * depending on the handshake parameters. Further, it is used for checking + * MD5-signed certificates, and for PBKDF1 when decrypting PEM-encoded + * encrypted keys. + * + * \warning MD5 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_NET_C + * + * Enable the TCP and UDP over IPv6/IPv4 networking routines. + * + * \note This module only works on POSIX/Unix (including Linux, BSD and OS X) + * and Windows. For other platforms, you'll want to disable it, and write your + * own networking callbacks to be passed to \c mbedtls_ssl_set_bio(). + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/net_sockets.c + * + * This module provides networking routines. + */ +//#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +//#define MBEDTLS_PADLOCK_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +//#define MBEDTLS_PEM_WRITE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define MBEDTLS_PK_WRITE_C + +/** + * \def MBEDTLS_PKCS5_C + * + * Enable PKCS#5 functions. + * + * Module: library/pkcs5.c + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +//#define MBEDTLS_PKCS5_C + +/** + * \def MBEDTLS_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/pkcs11.c + * Caller: library/pk.c + * + * Requires: MBEDTLS_PK_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) + */ +//#define MBEDTLS_PKCS11_C + +/** + * \def MBEDTLS_PKCS12_C + * + * Enable PKCS#12 PBE functions. + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/pkparse.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * Can use: MBEDTLS_ARC4_C + * + * This module enables PKCS#12 functions. + */ +//#define MBEDTLS_PKCS12_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other module rely on it for a fixed snprintf implementation. + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_POLY1305_C + * + * Enable the Poly1305 MAC algorithm. + * + * Module: library/poly1305.c + * Caller: library/chachapoly.c + */ +//#define MBEDTLS_POLY1305_C + +/** + * \def MBEDTLS_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/ripemd160.c + * Caller: library/md.c + * + */ +//#define MBEDTLS_RIPEMD160_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * library/rsa_internal.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS up to version 1.1, for TLS 1.2 + * depending on the handshake parameters, and for SHA1-signed certificates. + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/sha256.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/sha512.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +//#define MBEDTLS_SHA512_C + +/** + * \def MBEDTLS_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: MBEDTLS_SSL_CACHE_C + */ +//#define MBEDTLS_SSL_CACHE_C + +/** + * \def MBEDTLS_SSL_COOKIE_C + * + * Enable basic implementation of DTLS cookies for hello verification. + * + * Module: library/ssl_cookie.c + * Caller: + */ +//#define MBEDTLS_SSL_COOKIE_C + +/** + * \def MBEDTLS_SSL_TICKET_C + * + * Enable an implementation of TLS server-side callbacks for session tickets. + * + * Module: library/ssl_ticket.c + * Caller: + * + * Requires: MBEDTLS_CIPHER_C + */ +//#define MBEDTLS_SSL_TICKET_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +//#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_THREADING_C + * + * Enable the threading abstraction layer. + * By default mbed TLS assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. See also our Knowledge Base article about threading: + * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either MBEDTLS_THREADING_ALT or + * MBEDTLS_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within mbed TLS + */ +#define MBEDTLS_THREADING_C + +/** + * \def MBEDTLS_TIMING_C + * + * Enable the semi-portable timing interface. + * + * \note The provided implementation only works on POSIX/Unix (including Linux, + * BSD and OS X) and Windows. On other platforms, you can either disable that + * module and provide your own implementations of the callbacks needed by + * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide + * your own implementation of the whole module by setting + * \c MBEDTLS_TIMING_ALT in the current file. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +//#define MBEDTLS_TIMING_C + +/** + * \def MBEDTLS_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define MBEDTLS_VERSION_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/** + * \def MBEDTLS_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/x509_crl.c + * Caller: library/x509_crt.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +//#define MBEDTLS_X509_CRL_PARSE_C + +/** + * \def MBEDTLS_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +//#define MBEDTLS_X509_CSR_PARSE_C + +/** + * \def MBEDTLS_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +//#define MBEDTLS_X509_CREATE_C + +/** + * \def MBEDTLS_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +//#define MBEDTLS_X509_CRT_WRITE_C + +/** + * \def MBEDTLS_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +//#define MBEDTLS_X509_CSR_WRITE_C + +/** + * \def MBEDTLS_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +//#define MBEDTLS_XTEA_C + +/* \} name SECTION: mbed TLS modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +//#define MBEDTLS_CTR_DRBG_USE_128_BIT_KEY /**< Use 128-bit key for CTR_DRBG - may reduce security (see ctr_drbg.h) */ + +/* HMAC_DRBG options */ +//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */ + +/* Memory buffer allocator options */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */ + +/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ + +/** + * \brief This macro is invoked by the library when an invalid parameter + * is detected that is only checked with MBEDTLS_CHECK_PARAMS + * (see the documentation of that option for context). + * + * When you leave this undefined here, a default definition is + * provided that invokes the function mbedtls_param_failed(), + * which is declared in platform_util.h for the benefit of the + * library, but that you need to define in your application. + * + * When you define this here, this replaces the default + * definition in platform_util.h (which no longer declares the + * function mbedtls_param_failed()) and it is your responsibility + * to make sure this macro expands to something suitable (in + * particular, that all the necessary declarations are visible + * from within the library - you can ensure that by providing + * them in this file next to the macro definition). + * + * Note that you may define this macro to expand to nothing, in + * which case you don't have to worry about declarations or + * definitions. However, you will then be notified about invalid + * parameters only in non-void functions, and void function will + * just silently return early on invalid parameters, which + * partially negates the benefits of enabling + * #MBEDTLS_CHECK_PARAMS in the first place, so is discouraged. + * + * \param cond The expression that should evaluate to true, but doesn't. + */ +//#define MBEDTLS_PARAM_FAILED( cond ) assert( cond ) + +/* SSL Cache options */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ + +/** \def MBEDTLS_SSL_MAX_CONTENT_LEN + * + * Maximum length (in bytes) of incoming and outgoing plaintext fragments. + * + * This determines the size of both the incoming and outgoing TLS I/O buffers + * in such a way that both are capable of holding the specified amount of + * plaintext data, regardless of the protection mechanism used. + * + * To configure incoming and outgoing I/O buffers separately, use + * #MBEDTLS_SSL_IN_CONTENT_LEN and #MBEDTLS_SSL_OUT_CONTENT_LEN, + * which overwrite the value set by this option. + * + * \note When using a value less than the default of 16KB on the client, it is + * recommended to use the Maximum Fragment Length (MFL) extension to + * inform the server about this limitation. On the server, there + * is no supported, standardized way of informing the client about + * restriction on the maximum size of incoming messages, and unless + * the limitation has been communicated by other means, it is recommended + * to only change the outgoing buffer size #MBEDTLS_SSL_OUT_CONTENT_LEN + * while keeping the default value of 16KB for the incoming buffer. + * + * Uncomment to set the maximum plaintext size of both + * incoming and outgoing I/O buffers. + */ +#define MBEDTLS_SSL_MAX_CONTENT_LEN 8192 + +/** \def MBEDTLS_SSL_IN_CONTENT_LEN + * + * Maximum length (in bytes) of incoming plaintext fragments. + * + * This determines the size of the incoming TLS I/O buffer in such a way + * that it is capable of holding the specified amount of plaintext data, + * regardless of the protection mechanism used. + * + * If this option is undefined, it inherits its value from + * #MBEDTLS_SSL_MAX_CONTENT_LEN. + * + * \note When using a value less than the default of 16KB on the client, it is + * recommended to use the Maximum Fragment Length (MFL) extension to + * inform the server about this limitation. On the server, there + * is no supported, standardized way of informing the client about + * restriction on the maximum size of incoming messages, and unless + * the limitation has been communicated by other means, it is recommended + * to only change the outgoing buffer size #MBEDTLS_SSL_OUT_CONTENT_LEN + * while keeping the default value of 16KB for the incoming buffer. + * + * Uncomment to set the maximum plaintext size of the incoming I/O buffer + * independently of the outgoing I/O buffer. + */ +//#define MBEDTLS_SSL_IN_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_OUT_CONTENT_LEN + * + * Maximum length (in bytes) of outgoing plaintext fragments. + * + * This determines the size of the outgoing TLS I/O buffer in such a way + * that it is capable of holding the specified amount of plaintext data, + * regardless of the protection mechanism used. + * + * If this option undefined, it inherits its value from + * #MBEDTLS_SSL_MAX_CONTENT_LEN. + * + * It is possible to save RAM by setting a smaller outward buffer, while keeping + * the default inward 16384 byte buffer to conform to the TLS specification. + * + * The minimum required outward buffer size is determined by the handshake + * protocol's usage. Handshaking will fail if the outward buffer is too small. + * The specific size requirement depends on the configured ciphers and any + * certificate data which is sent during the handshake. + * + * Uncomment to set the maximum plaintext size of the outgoing I/O buffer + * independently of the incoming I/O buffer. + */ +//#define MBEDTLS_SSL_OUT_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_DTLS_MAX_BUFFERING + * + * Maximum number of heap-allocated bytes for the purpose of + * DTLS handshake message reassembly and future message buffering. + * + * This should be at least 9/8 * MBEDTLSSL_IN_CONTENT_LEN + * to account for a reassembled handshake message of maximum size, + * together with its reassembly bitmap. + * + * A value of 2 * MBEDTLS_SSL_IN_CONTENT_LEN (32768 by default) + * should be sufficient for all practical situations as it allows + * to reassembly a large handshake message (such as a certificate) + * while buffering multiple smaller handshake messages. + * + */ +//#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768 + +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + +/* X509 options */ +//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ +//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */ + +/** + * Allow SHA-1 in the default TLS configuration for certificate signing. + * Without this build-time option, SHA-1 support must be activated explicitly + * through mbedtls_ssl_conf_cert_profile. Turning on this option is not + * recommended because of it is possible to generate SHA-1 collisions, however + * this may be safe for legacy infrastructure where additional controls apply. + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES + +/** + * Allow SHA-1 in the default TLS configuration for TLS 1.2 handshake + * signature and ciphersuite selection. Without this build-time option, SHA-1 + * support must be activated explicitly through mbedtls_ssl_conf_sig_hashes. + * The use of SHA-1 in TLS <= 1.1 and in HMAC-SHA-1 is always allowed by + * default. At the time of writing, there is no practical attack on the use + * of SHA-1 in handshake signatures, hence this option is turned on by default + * to preserve compatibility with existing peers, but the general + * warning applies nonetheless: + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE + +/** + * Uncomment the macro to let mbed TLS use your alternate implementation of + * mbedtls_platform_zeroize(). This replaces the default implementation in + * platform_util.c. + * + * mbedtls_platform_zeroize() is a widely used function across the library to + * zero a block of memory. The implementation is expected to be secure in the + * sense that it has been written to prevent the compiler from removing calls + * to mbedtls_platform_zeroize() as part of redundant code elimination + * optimizations. However, it is difficult to guarantee that calls to + * mbedtls_platform_zeroize() will not be optimized by the compiler as older + * versions of the C language standards do not provide a secure implementation + * of memset(). Therefore, MBEDTLS_PLATFORM_ZEROIZE_ALT enables users to + * configure their own implementation of mbedtls_platform_zeroize(), for + * example by using directives specific to their compiler, features from newer + * C standards (e.g using memset_s() in C11) or calling a secure memset() from + * their system (e.g explicit_bzero() in BSD). + */ +//#define MBEDTLS_PLATFORM_ZEROIZE_ALT + +/** + * Uncomment the macro to let Mbed TLS use your alternate implementation of + * mbedtls_platform_gmtime_r(). This replaces the default implementation in + * platform_util.c. + * + * gmtime() is not a thread-safe function as defined in the C standard. The + * library will try to use safer implementations of this function, such as + * gmtime_r() when available. However, if Mbed TLS cannot identify the target + * system, the implementation of mbedtls_platform_gmtime_r() will default to + * using the standard gmtime(). In this case, calls from the library to + * gmtime() will be guarded by the global mutex mbedtls_threading_gmtime_mutex + * if MBEDTLS_THREADING_C is enabled. We recommend that calls from outside the + * library are also guarded with this mutex to avoid race conditions. However, + * if the macro MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, Mbed TLS will + * unconditionally use the implementation for mbedtls_platform_gmtime_r() + * supplied at compile time. + */ +//#define MBEDTLS_PLATFORM_GMTIME_R_ALT + +/* \} name SECTION: Customisation configuration options */ + +/* Target and application specific configurations + * + * Allow user to override any previous default. + */ +#if defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/entropy_poll.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/entropy_poll.h index 94dd657..c4fa20e 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/entropy_poll.h +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/entropy_poll.h @@ -60,6 +60,9 @@ extern "C" { */ int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len, size_t *olen ); +#else +int mbedtls_random_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); #endif #if defined(MBEDTLS_HAVEGE_C) diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/poly1305.h b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/poly1305.h new file mode 100644 index 0000000..f0ec44c --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/include/mbedtls/poly1305.h @@ -0,0 +1,192 @@ +/** + * \file poly1305.h + * + * \brief This file contains Poly1305 definitions and functions. + * + * Poly1305 is a one-time message authenticator that can be used to + * authenticate messages. Poly1305-AES was created by Daniel + * Bernstein https://cr.yp.to/mac/poly1305-20050329.pdf The generic + * Poly1305 algorithm (not tied to AES) was also standardized in RFC + * 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_POLY1305_H +#define MBEDTLS_POLY1305_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA -0x0057 /**< Invalid input parameter(s). */ + +/* MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE is deprecated and should not be + * used. */ +#define MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE -0x0059 /**< Feature not available. For example, s part of the API is not implemented. */ + +/* MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED -0x005B /**< Poly1305 hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_POLY1305_ALT) + +typedef struct mbedtls_poly1305_context +{ + uint32_t r[4]; /** The value for 'r' (low 128 bits of the key). */ + uint32_t s[4]; /** The value for 's' (high 128 bits of the key). */ + uint32_t acc[5]; /** The accumulator number. */ + uint8_t queue[16]; /** The current partial block of data. */ + size_t queue_len; /** The number of bytes stored in 'queue'. */ +} +mbedtls_poly1305_context; + +#else /* MBEDTLS_POLY1305_ALT */ +#include "poly1305_alt.h" +#endif /* MBEDTLS_POLY1305_ALT */ + +/** + * \brief This function initializes the specified Poly1305 context. + * + * It must be the first API called before using + * the context. + * + * It is usually followed by a call to + * \c mbedtls_poly1305_starts(), then one or more calls to + * \c mbedtls_poly1305_update(), then one call to + * \c mbedtls_poly1305_finish(), then finally + * \c mbedtls_poly1305_free(). + * + * \param ctx The Poly1305 context to initialize. This must + * not be \c NULL. + */ +void mbedtls_poly1305_init( mbedtls_poly1305_context *ctx ); + +/** + * \brief This function releases and clears the specified + * Poly1305 context. + * + * \param ctx The Poly1305 context to clear. This may be \c NULL, in which + * case this function is a no-op. If it is not \c NULL, it must + * point to an initialized Poly1305 context. + */ +void mbedtls_poly1305_free( mbedtls_poly1305_context *ctx ); + +/** + * \brief This function sets the one-time authentication key. + * + * \warning The key must be unique and unpredictable for each + * invocation of Poly1305. + * + * \param ctx The Poly1305 context to which the key should be bound. + * This must be initialized. + * \param key The buffer containing the \c 32 Byte (\c 256 Bit) key. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_starts( mbedtls_poly1305_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This functions feeds an input buffer into an ongoing + * Poly1305 computation. + * + * It is called between \c mbedtls_cipher_poly1305_starts() and + * \c mbedtls_cipher_poly1305_finish(). + * It can be called repeatedly to process a stream of data. + * + * \param ctx The Poly1305 context to use for the Poly1305 operation. + * This must be initialized and bound to a key. + * \param ilen The length of the input data in Bytes. + * Any value is accepted. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `ilen == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_update( mbedtls_poly1305_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function generates the Poly1305 Message + * Authentication Code (MAC). + * + * \param ctx The Poly1305 context to use for the Poly1305 operation. + * This must be initialized and bound to a key. + * \param mac The buffer to where the MAC is written. This must + * be a writable buffer of length \c 16 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_finish( mbedtls_poly1305_context *ctx, + unsigned char mac[16] ); + +/** + * \brief This function calculates the Poly1305 MAC of the input + * buffer with the provided key. + * + * \warning The key must be unique and unpredictable for each + * invocation of Poly1305. + * + * \param key The buffer containing the \c 32 Byte (\c 256 Bit) key. + * \param ilen The length of the input data in Bytes. + * Any value is accepted. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `ilen == 0`. + * \param mac The buffer to where the MAC is written. This must be + * a writable buffer of length \c 16 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_mac( const unsigned char key[32], + const unsigned char *input, + size_t ilen, + unsigned char mac[16] ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The Poly1305 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_poly1305_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_POLY1305_H */ diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/chacha20.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/chacha20.c new file mode 100644 index 0000000..8a3610f --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/chacha20.c @@ -0,0 +1,570 @@ +/** + * \file chacha20.c + * + * \brief ChaCha20 cipher. + * + * \author Daniel King + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CHACHA20_C) + +#include "mbedtls/chacha20.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CHACHA20_ALT) + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Parameter validation macros */ +#define CHACHA20_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA ) +#define CHACHA20_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define BYTES_TO_U32_LE( data, offset ) \ + ( (uint32_t) (data)[offset] \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \ + ) + +#define ROTL32( value, amount ) \ + ( (uint32_t) ( (value) << (amount) ) | ( (value) >> ( 32 - (amount) ) ) ) + +#define CHACHA20_CTR_INDEX ( 12U ) + +#define CHACHA20_BLOCK_SIZE_BYTES ( 4U * 16U ) + +/** + * \brief ChaCha20 quarter round operation. + * + * The quarter round is defined as follows (from RFC 7539): + * 1. a += b; d ^= a; d <<<= 16; + * 2. c += d; b ^= c; b <<<= 12; + * 3. a += b; d ^= a; d <<<= 8; + * 4. c += d; b ^= c; b <<<= 7; + * + * \param state ChaCha20 state to modify. + * \param a The index of 'a' in the state. + * \param b The index of 'b' in the state. + * \param c The index of 'c' in the state. + * \param d The index of 'd' in the state. + */ +static inline void chacha20_quarter_round( uint32_t state[16], + size_t a, + size_t b, + size_t c, + size_t d ) +{ + /* a += b; d ^= a; d <<<= 16; */ + state[a] += state[b]; + state[d] ^= state[a]; + state[d] = ROTL32( state[d], 16 ); + + /* c += d; b ^= c; b <<<= 12 */ + state[c] += state[d]; + state[b] ^= state[c]; + state[b] = ROTL32( state[b], 12 ); + + /* a += b; d ^= a; d <<<= 8; */ + state[a] += state[b]; + state[d] ^= state[a]; + state[d] = ROTL32( state[d], 8 ); + + /* c += d; b ^= c; b <<<= 7; */ + state[c] += state[d]; + state[b] ^= state[c]; + state[b] = ROTL32( state[b], 7 ); +} + +/** + * \brief Perform the ChaCha20 inner block operation. + * + * This function performs two rounds: the column round and the + * diagonal round. + * + * \param state The ChaCha20 state to update. + */ +static void chacha20_inner_block( uint32_t state[16] ) +{ + chacha20_quarter_round( state, 0, 4, 8, 12 ); + chacha20_quarter_round( state, 1, 5, 9, 13 ); + chacha20_quarter_round( state, 2, 6, 10, 14 ); + chacha20_quarter_round( state, 3, 7, 11, 15 ); + + chacha20_quarter_round( state, 0, 5, 10, 15 ); + chacha20_quarter_round( state, 1, 6, 11, 12 ); + chacha20_quarter_round( state, 2, 7, 8, 13 ); + chacha20_quarter_round( state, 3, 4, 9, 14 ); +} + +/** + * \brief Generates a keystream block. + * + * \param initial_state The initial ChaCha20 state (key, nonce, counter). + * \param keystream Generated keystream bytes are written to this buffer. + */ +static void chacha20_block( const uint32_t initial_state[16], + unsigned char keystream[64] ) +{ + uint32_t working_state[16]; + size_t i; + + memcpy( working_state, + initial_state, + CHACHA20_BLOCK_SIZE_BYTES ); + + for( i = 0U; i < 10U; i++ ) + chacha20_inner_block( working_state ); + + working_state[ 0] += initial_state[ 0]; + working_state[ 1] += initial_state[ 1]; + working_state[ 2] += initial_state[ 2]; + working_state[ 3] += initial_state[ 3]; + working_state[ 4] += initial_state[ 4]; + working_state[ 5] += initial_state[ 5]; + working_state[ 6] += initial_state[ 6]; + working_state[ 7] += initial_state[ 7]; + working_state[ 8] += initial_state[ 8]; + working_state[ 9] += initial_state[ 9]; + working_state[10] += initial_state[10]; + working_state[11] += initial_state[11]; + working_state[12] += initial_state[12]; + working_state[13] += initial_state[13]; + working_state[14] += initial_state[14]; + working_state[15] += initial_state[15]; + + for( i = 0U; i < 16; i++ ) + { + size_t offset = i * 4U; + + keystream[offset ] = (unsigned char)( working_state[i] ); + keystream[offset + 1U] = (unsigned char)( working_state[i] >> 8 ); + keystream[offset + 2U] = (unsigned char)( working_state[i] >> 16 ); + keystream[offset + 3U] = (unsigned char)( working_state[i] >> 24 ); + } + + mbedtls_platform_zeroize( working_state, sizeof( working_state ) ); +} + +void mbedtls_chacha20_init( mbedtls_chacha20_context *ctx ) +{ + CHACHA20_VALIDATE( ctx != NULL ); + + mbedtls_platform_zeroize( ctx->state, sizeof( ctx->state ) ); + mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) ); + + /* Initially, there's no keystream bytes available */ + ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES; +} + +void mbedtls_chacha20_free( mbedtls_chacha20_context *ctx ) +{ + if( ctx != NULL ) + { + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_chacha20_context ) ); + } +} + +int mbedtls_chacha20_setkey( mbedtls_chacha20_context *ctx, + const unsigned char key[32] ) +{ + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( key != NULL ); + + /* ChaCha20 constants - the string "expand 32-byte k" */ + ctx->state[0] = 0x61707865; + ctx->state[1] = 0x3320646e; + ctx->state[2] = 0x79622d32; + ctx->state[3] = 0x6b206574; + + /* Set key */ + ctx->state[4] = BYTES_TO_U32_LE( key, 0 ); + ctx->state[5] = BYTES_TO_U32_LE( key, 4 ); + ctx->state[6] = BYTES_TO_U32_LE( key, 8 ); + ctx->state[7] = BYTES_TO_U32_LE( key, 12 ); + ctx->state[8] = BYTES_TO_U32_LE( key, 16 ); + ctx->state[9] = BYTES_TO_U32_LE( key, 20 ); + ctx->state[10] = BYTES_TO_U32_LE( key, 24 ); + ctx->state[11] = BYTES_TO_U32_LE( key, 28 ); + + return( 0 ); +} + +int mbedtls_chacha20_starts( mbedtls_chacha20_context* ctx, + const unsigned char nonce[12], + uint32_t counter ) +{ + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( nonce != NULL ); + + /* Counter */ + ctx->state[12] = counter; + + /* Nonce */ + ctx->state[13] = BYTES_TO_U32_LE( nonce, 0 ); + ctx->state[14] = BYTES_TO_U32_LE( nonce, 4 ); + ctx->state[15] = BYTES_TO_U32_LE( nonce, 8 ); + + mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) ); + + /* Initially, there's no keystream bytes available */ + ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES; + + return( 0 ); +} + +int mbedtls_chacha20_update( mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output ) +{ + size_t offset = 0U; + size_t i; + + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( size == 0 || input != NULL ); + CHACHA20_VALIDATE_RET( size == 0 || output != NULL ); + + /* Use leftover keystream bytes, if available */ + while( size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES ) + { + output[offset] = input[offset] + ^ ctx->keystream8[ctx->keystream_bytes_used]; + + ctx->keystream_bytes_used++; + offset++; + size--; + } + + /* Process full blocks */ + while( size >= CHACHA20_BLOCK_SIZE_BYTES ) + { + /* Generate new keystream block and increment counter */ + chacha20_block( ctx->state, ctx->keystream8 ); + ctx->state[CHACHA20_CTR_INDEX]++; + + for( i = 0U; i < 64U; i += 8U ) + { + output[offset + i ] = input[offset + i ] ^ ctx->keystream8[i ]; + output[offset + i+1] = input[offset + i+1] ^ ctx->keystream8[i+1]; + output[offset + i+2] = input[offset + i+2] ^ ctx->keystream8[i+2]; + output[offset + i+3] = input[offset + i+3] ^ ctx->keystream8[i+3]; + output[offset + i+4] = input[offset + i+4] ^ ctx->keystream8[i+4]; + output[offset + i+5] = input[offset + i+5] ^ ctx->keystream8[i+5]; + output[offset + i+6] = input[offset + i+6] ^ ctx->keystream8[i+6]; + output[offset + i+7] = input[offset + i+7] ^ ctx->keystream8[i+7]; + } + + offset += CHACHA20_BLOCK_SIZE_BYTES; + size -= CHACHA20_BLOCK_SIZE_BYTES; + } + + /* Last (partial) block */ + if( size > 0U ) + { + /* Generate new keystream block and increment counter */ + chacha20_block( ctx->state, ctx->keystream8 ); + ctx->state[CHACHA20_CTR_INDEX]++; + + for( i = 0U; i < size; i++) + { + output[offset + i] = input[offset + i] ^ ctx->keystream8[i]; + } + + ctx->keystream_bytes_used = size; + + } + + return( 0 ); +} + +int mbedtls_chacha20_crypt( const unsigned char key[32], + const unsigned char nonce[12], + uint32_t counter, + size_t data_len, + const unsigned char* input, + unsigned char* output ) +{ + mbedtls_chacha20_context ctx; + int ret; + + CHACHA20_VALIDATE_RET( key != NULL ); + CHACHA20_VALIDATE_RET( nonce != NULL ); + CHACHA20_VALIDATE_RET( data_len == 0 || input != NULL ); + CHACHA20_VALIDATE_RET( data_len == 0 || output != NULL ); + + mbedtls_chacha20_init( &ctx ); + + ret = mbedtls_chacha20_setkey( &ctx, key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chacha20_starts( &ctx, nonce, counter ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chacha20_update( &ctx, data_len, input, output ); + +cleanup: + mbedtls_chacha20_free( &ctx ); + return( ret ); +} + +#endif /* !MBEDTLS_CHACHA20_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_keys[2][32] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } +}; + +static const unsigned char test_nonces[2][12] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02 + } +}; + +static const uint32_t test_counters[2] = +{ + 0U, + 1U +}; + +static const unsigned char test_input[2][375] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + { + 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, + 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, + 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, + 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f + } +}; + +static const unsigned char test_output[2][375] = +{ + { + 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, + 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, + 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, + 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, + 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, + 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, + 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, + 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86 + }, + { + 0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde, + 0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70, + 0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd, + 0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec, + 0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15, + 0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05, + 0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f, + 0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d, + 0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa, + 0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e, + 0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7, + 0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50, + 0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05, + 0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c, + 0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05, + 0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a, + 0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0, + 0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66, + 0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4, + 0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d, + 0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91, + 0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28, + 0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87, + 0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b, + 0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2, + 0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f, + 0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76, + 0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c, + 0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b, + 0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84, + 0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd, + 0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b, + 0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe, + 0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0, + 0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80, + 0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f, + 0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3, + 0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62, + 0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91, + 0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6, + 0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64, + 0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85, + 0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41, + 0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab, + 0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba, + 0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd, + 0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21 + } +}; + +static const size_t test_lengths[2] = +{ + 64U, + 375U +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_chacha20_self_test( int verbose ) +{ + unsigned char output[381]; + unsigned i; + int ret; + + for( i = 0U; i < 2U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ChaCha20 test %u ", i ); + + ret = mbedtls_chacha20_crypt( test_keys[i], + test_nonces[i], + test_counters[i], + test_lengths[i], + test_input[i], + output ); + + ASSERT( 0 == ret, ( "error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( output, test_output[i], test_lengths[i] ), + ( "failed (output)\n" ) ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* !MBEDTLS_CHACHA20_C */ diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/chachapoly.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/chachapoly.c new file mode 100644 index 0000000..dc643dd --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/chachapoly.c @@ -0,0 +1,540 @@ +/** + * \file chachapoly.c + * + * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539. + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + +#include "mbedtls/chachapoly.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CHACHAPOLY_ALT) + +/* Parameter validation macros */ +#define CHACHAPOLY_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA ) +#define CHACHAPOLY_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define CHACHAPOLY_STATE_INIT ( 0 ) +#define CHACHAPOLY_STATE_AAD ( 1 ) +#define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */ +#define CHACHAPOLY_STATE_FINISHED ( 3 ) + +/** + * \brief Adds nul bytes to pad the AAD for Poly1305. + * + * \param ctx The ChaCha20-Poly1305 context. + */ +static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx ) +{ + uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U ); + unsigned char zeroes[15]; + + if( partial_block_len == 0U ) + return( 0 ); + + memset( zeroes, 0, sizeof( zeroes ) ); + + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, + zeroes, + 16U - partial_block_len ) ); +} + +/** + * \brief Adds nul bytes to pad the ciphertext for Poly1305. + * + * \param ctx The ChaCha20-Poly1305 context. + */ +static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx ) +{ + uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U ); + unsigned char zeroes[15]; + + if( partial_block_len == 0U ) + return( 0 ); + + memset( zeroes, 0, sizeof( zeroes ) ); + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, + zeroes, + 16U - partial_block_len ) ); +} + +void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx ) +{ + CHACHAPOLY_VALIDATE( ctx != NULL ); + + mbedtls_chacha20_init( &ctx->chacha20_ctx ); + mbedtls_poly1305_init( &ctx->poly1305_ctx ); + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_INIT; + ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT; +} + +void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_chacha20_free( &ctx->chacha20_ctx ); + mbedtls_poly1305_free( &ctx->poly1305_ctx ); + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_INIT; + ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT; +} + +int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx, + const unsigned char key[32] ) +{ + int ret; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( key != NULL ); + + ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key ); + + return( ret ); +} + +int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx, + const unsigned char nonce[12], + mbedtls_chachapoly_mode_t mode ) +{ + int ret; + unsigned char poly1305_key[64]; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + + /* Set counter = 0, will be update to 1 when generating Poly1305 key */ + ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U ); + if( ret != 0 ) + goto cleanup; + + /* Generate the Poly1305 key by getting the ChaCha20 keystream output with + * counter = 0. This is the same as encrypting a buffer of zeroes. + * Only the first 256-bits (32 bytes) of the key is used for Poly1305. + * The other 256 bits are discarded. + */ + memset( poly1305_key, 0, sizeof( poly1305_key ) ); + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ), + poly1305_key, poly1305_key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key ); + + if( ret == 0 ) + { + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_AAD; + ctx->mode = mode; + } + +cleanup: + mbedtls_platform_zeroize( poly1305_key, 64U ); + return( ret ); +} + +int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx, + const unsigned char *aad, + size_t aad_len ) +{ + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + + if( ctx->state != CHACHAPOLY_STATE_AAD ) + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + + ctx->aad_len += aad_len; + + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) ); +} + +int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx, + size_t len, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( len == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( len == 0 || output != NULL ); + + if( ( ctx->state != CHACHAPOLY_STATE_AAD ) && + ( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) ) + { + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + } + + if( ctx->state == CHACHAPOLY_STATE_AAD ) + { + ctx->state = CHACHAPOLY_STATE_CIPHERTEXT; + + ret = chachapoly_pad_aad( ctx ); + if( ret != 0 ) + return( ret ); + } + + ctx->ciphertext_len += len; + + if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT ) + { + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len ); + if( ret != 0 ) + return( ret ); + } + else /* DECRYPT */ + { + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output ); + if( ret != 0 ) + return( ret ); + } + + return( 0 ); +} + +int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, + unsigned char mac[16] ) +{ + int ret; + unsigned char len_block[16]; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( mac != NULL ); + + if( ctx->state == CHACHAPOLY_STATE_INIT ) + { + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + } + + if( ctx->state == CHACHAPOLY_STATE_AAD ) + { + ret = chachapoly_pad_aad( ctx ); + if( ret != 0 ) + return( ret ); + } + else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT ) + { + ret = chachapoly_pad_ciphertext( ctx ); + if( ret != 0 ) + return( ret ); + } + + ctx->state = CHACHAPOLY_STATE_FINISHED; + + /* The lengths of the AAD and ciphertext are processed by + * Poly1305 as the final 128-bit block, encoded as little-endian integers. + */ + len_block[ 0] = (unsigned char)( ctx->aad_len ); + len_block[ 1] = (unsigned char)( ctx->aad_len >> 8 ); + len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 ); + len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 ); + len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 ); + len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 ); + len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 ); + len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 ); + len_block[ 8] = (unsigned char)( ctx->ciphertext_len ); + len_block[ 9] = (unsigned char)( ctx->ciphertext_len >> 8 ); + len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 ); + len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 ); + len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 ); + len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 ); + len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 ); + len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 ); + + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac ); + + return( ret ); +} + +static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx, + mbedtls_chachapoly_mode_t mode, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ) +{ + int ret; + + ret = mbedtls_chachapoly_starts( ctx, nonce, mode ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_update( ctx, length, input, output ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_finish( ctx, tag ); + +cleanup: + return( ret ); +} + +int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ) +{ + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + CHACHAPOLY_VALIDATE_RET( tag != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL ); + + return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT, + length, nonce, aad, aad_len, + input, output, tag ) ); +} + +int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char tag[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char check_tag[16]; + size_t i; + int diff; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + CHACHAPOLY_VALIDATE_RET( tag != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL ); + + if( ( ret = chachapoly_crypt_and_tag( ctx, + MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce, + aad, aad_len, input, output, check_tag ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < sizeof( check_tag ); i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_platform_zeroize( output, length ); + return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_CHACHAPOLY_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_key[1][32] = +{ + { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + } +}; + +static const unsigned char test_nonce[1][12] = +{ + { + 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */ + } +}; + +static const unsigned char test_aad[1][12] = +{ + { + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7 + } +}; + +static const size_t test_aad_len[1] = +{ + 12U +}; + +static const unsigned char test_input[1][114] = +{ + { + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, + 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, + 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, + 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, + 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, + 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x74, 0x2e + } +}; + +static const unsigned char test_output[1][114] = +{ + { + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, + 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, + 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, + 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, + 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, + 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, + 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, + 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16 + } +}; + +static const size_t test_input_len[1] = +{ + 114U +}; + +static const unsigned char test_mac[1][16] = +{ + { + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, + 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91 + } +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_chachapoly_self_test( int verbose ) +{ + mbedtls_chachapoly_context ctx; + unsigned i; + int ret; + unsigned char output[200]; + unsigned char mac[16]; + + for( i = 0U; i < 1U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ChaCha20-Poly1305 test %u ", i ); + + mbedtls_chachapoly_init( &ctx ); + + ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] ); + ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) ); + + ret = mbedtls_chachapoly_encrypt_and_tag( &ctx, + test_input_len[i], + test_nonce[i], + test_aad[i], + test_aad_len[i], + test_input[i], + output, + mac ); + + ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ), + ( "failure (wrong output)\n" ) ); + + ASSERT( 0 == memcmp( mac, test_mac[i], 16U ), + ( "failure (wrong MAC)\n" ) ); + + mbedtls_chachapoly_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CHACHAPOLY_C */ diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/ctr_drbg.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/ctr_drbg.c index fb12157..4d487b2 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/ctr_drbg.c +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/ctr_drbg.c @@ -376,6 +376,8 @@ void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, * and with output * ctx contains new_working_state */ +int mbedtls_random_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, const unsigned char *additional, size_t len ) { diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/debug.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/debug.c index 824cd02..26b2f05 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/debug.c +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/debug.c @@ -108,7 +108,7 @@ void mbedtls_debug_print_msg( const mbedtls_ssl_context *ssl, int level, if( ret >= 0 && ret < DEBUG_BUF_SIZE - 1 ) { - str[ret] = '\n'; + str[ret] = '\0'; str[ret + 1] = '\0'; } diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/entropy.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/entropy.c index f8db1a5..e85f928 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/entropy.c +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/entropy.c @@ -94,6 +94,10 @@ void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL, MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_SOURCE_STRONG ); +#else + mbedtls_entropy_add_source( ctx, mbedtls_random_entropy_poll, NULL, + MBEDTLS_ENTROPY_MIN_PLATFORM, + MBEDTLS_ENTROPY_SOURCE_STRONG ); #endif #if defined(MBEDTLS_TIMING_C) mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL, diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/entropy_poll.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/entropy_poll.c index 4556f88..528f20e 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/entropy_poll.c +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/entropy_poll.c @@ -157,6 +157,27 @@ int mbedtls_platform_entropy_poll( void *data, return( 0 ); } #endif /* _WIN32 && !EFIX64 && !EFI32 */ +#else +#include +int mbedtls_random_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + ((void) data); + *olen = 0; + size_t tlen = 0; + int rnd_val; + int remain = len; + int n; + while (remain > 0) { + rnd_val = rand(); + n = ((len - tlen) > 4) ? 4 : (len - tlen); + memcpy(output, (unsigned char *)&rnd_val, n); + remain -= n; + } + *olen = len; + + return( 0 ); +} #endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ #if defined(MBEDTLS_TEST_NULL_ENTROPY) diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/net_sockets.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/net_sockets.c index 816b130..401cbec 100644 --- a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/net_sockets.c +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/net_sockets.c @@ -1,7 +1,10 @@ /* * TCP/IP or UDP/IP networking functions + * modified for LWIP support on K210 * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Additions Copyright (C) 2015 Angus Gratton + * Additions Copyright (C) 2020 LoBo * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -19,94 +22,34 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ -/* Enable definition of getaddrinfo() even when compiling with -std=c99. Must - * be set before config.h, which pulls in glibc's features.h indirectly. - * Harmless on other platforms. */ -#define _POSIX_C_SOURCE 200112L - #if !defined(MBEDTLS_CONFIG_FILE) #include "mbedtls/config.h" #else #include MBEDTLS_CONFIG_FILE #endif -#if defined(MBEDTLS_NET_C) - -#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ - !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ - !defined(__HAIKU__) -#error "This module only works on Unix and Windows, see MBEDTLS_NET_C in config.h" -#endif +#if !defined(MBEDTLS_NET_C) #if defined(MBEDTLS_PLATFORM_C) #include "mbedtls/platform.h" #else #include +#define mbedtls_calloc calloc +#define mbedtls_free free +#define mbedtls_time time +#define mbedtls_time_t time_t #endif #include "mbedtls/net_sockets.h" +#include "lwip/sockets.h" +#include "lwip/netdb.h" #include - -#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ - !defined(EFI32) - -#define IS_EINTR( ret ) ( ( ret ) == WSAEINTR ) - -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501) -#undef _WIN32_WINNT -/* Enables getaddrinfo() & Co */ -#define _WIN32_WINNT 0x0501 -#endif - -#include - -#include -#include - -#if defined(_MSC_VER) -#if defined(_WIN32_WCE) -#pragma comment( lib, "ws2.lib" ) -#else -#pragma comment( lib, "ws2_32.lib" ) -#endif -#endif /* _MSC_VER */ - -#define read(fd,buf,len) recv( fd, (char*)( buf ), (int)( len ), 0 ) -#define write(fd,buf,len) send( fd, (char*)( buf ), (int)( len ), 0 ) -#define close(fd) closesocket(fd) - -static int wsa_init_done = 0; - -#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ - #include -#include -#include -#include -#include #include -#include -#include -#include -#include - -#define IS_EINTR( ret ) ( ( ret ) == EINTR ) - -#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ - -/* Some MS functions want int and MSVC warns if we pass size_t, - * but the standard functions use socklen_t, so cast only for MSVC */ -#if defined(_MSC_VER) -#define MSVC_INT_CAST (int) -#else -#define MSVC_INT_CAST -#endif - +#include #include - #include - #include /* @@ -114,23 +57,7 @@ static int wsa_init_done = 0; */ static int net_prepare( void ) { -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - WSADATA wsaData; - - if( wsa_init_done == 0 ) - { - if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) - return( MBEDTLS_ERR_NET_SOCKET_FAILED ); - - wsa_init_done = 1; - } -#else -#if !defined(EFIX64) && !defined(EFI32) - signal( SIGPIPE, SIG_IGN ); -#endif -#endif - return( 0 ); + return ( 0 ); } /* @@ -144,14 +71,14 @@ void mbedtls_net_init( mbedtls_net_context *ctx ) /* * Initiate a TCP connection with host:port and the given protocol */ -int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, - const char *port, int proto ) +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto ) { int ret; struct addrinfo hints, *addr_list, *cur; - if( ( ret = net_prepare() ) != 0 ) - return( ret ); + if ( ( ret = net_prepare() ) != 0 ) { + return ( ret ); + } /* Do name resolution with both IPv6 and IPv4 */ memset( &hints, 0, sizeof( hints ) ); @@ -159,34 +86,33 @@ int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; - if( getaddrinfo( host, port, &hints, &addr_list ) != 0 ) - return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + if ( lwip_getaddrinfo( host, port, &hints, &addr_list ) != 0 ) { + return ( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + } /* Try the sockaddrs until a connection succeeds */ ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; - for( cur = addr_list; cur != NULL; cur = cur->ai_next ) - { - ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, - cur->ai_protocol ); - if( ctx->fd < 0 ) - { + for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) { + int fd = lwip_socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol ); + + if ( fd < 0 ) { ret = MBEDTLS_ERR_NET_SOCKET_FAILED; continue; } - if( connect( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) == 0 ) - { + if ( lwip_connect( fd, cur->ai_addr, cur->ai_addrlen ) == 0 ) { + ctx->fd = fd; // connected! ret = 0; break; } - close( ctx->fd ); + close( fd ); ret = MBEDTLS_ERR_NET_CONNECT_FAILED; } - freeaddrinfo( addr_list ); + lwip_freeaddrinfo( addr_list ); - return( ret ); + return ( ret ); } /* @@ -194,85 +120,75 @@ int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, */ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ) { - int n, ret; + int ret; struct addrinfo hints, *addr_list, *cur; + struct sockaddr_in *serv_addr = NULL; +#if SO_REUSE + int n = 1; +#endif - if( ( ret = net_prepare() ) != 0 ) - return( ret ); + if ( ( ret = net_prepare() ) != 0 ) { + return ( ret ); + } /* Bind to IPv6 and/or IPv4, but only in the desired protocol */ memset( &hints, 0, sizeof( hints ) ); hints.ai_family = AF_UNSPEC; hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; - if( bind_ip == NULL ) - hints.ai_flags = AI_PASSIVE; - if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) - return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + if ( lwip_getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) { + return ( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + } /* Try the sockaddrs until a binding succeeds */ ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; - for( cur = addr_list; cur != NULL; cur = cur->ai_next ) - { - ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, - cur->ai_protocol ); - if( ctx->fd < 0 ) - { + for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) { + int fd = lwip_socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol ); + if ( fd < 0 ) { ret = MBEDTLS_ERR_NET_SOCKET_FAILED; continue; } - n = 1; - if( setsockopt( ctx->fd, SOL_SOCKET, SO_REUSEADDR, - (const char *) &n, sizeof( n ) ) != 0 ) - { - close( ctx->fd ); + /*SO_REUSEADDR option dafault is disable in source code(lwip)*/ +#if SO_REUSE + if ( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &n, sizeof( n ) ) != 0 ) { + close( fd ); ret = MBEDTLS_ERR_NET_SOCKET_FAILED; continue; } - - if( bind( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) != 0 ) - { - close( ctx->fd ); +#endif + /*bind interface dafault don't process the addr is 0xffffffff for TCP Protocol*/ + serv_addr = (struct sockaddr_in *)cur->ai_addr; + serv_addr->sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ + if ( lwip_bind( fd, (struct sockaddr *)serv_addr, cur->ai_addrlen ) != 0 ) { + close( fd ); ret = MBEDTLS_ERR_NET_BIND_FAILED; continue; } /* Listen only makes sense for TCP */ - if( proto == MBEDTLS_NET_PROTO_TCP ) - { - if( listen( ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) - { - close( ctx->fd ); + if ( proto == MBEDTLS_NET_PROTO_TCP ) { + if ( lwip_listen( fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) { + close( fd ); ret = MBEDTLS_ERR_NET_LISTEN_FAILED; continue; } } - /* Bind was successful */ + /* I we ever get there, it's a success */ + ctx->fd = fd; ret = 0; break; } - freeaddrinfo( addr_list ); + lwip_freeaddrinfo( addr_list ); - return( ret ); + return ( ret ); } -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) -/* - * Check if the requested operation would be blocking on a non-blocking socket - * and thus 'failed' with a negative return value. - */ -static int net_would_block( const mbedtls_net_context *ctx ) -{ - ((void) ctx); - return( WSAGetLastError() == WSAEWOULDBLOCK ); -} -#else /* * Check if the requested operation would be blocking on a non-blocking socket * and thus 'failed' with a negative return value. @@ -281,30 +197,19 @@ static int net_would_block( const mbedtls_net_context *ctx ) */ static int net_would_block( const mbedtls_net_context *ctx ) { - int err = errno; - - /* - * Never return 'WOULD BLOCK' on a non-blocking socket - */ - if( ( fcntl( ctx->fd, F_GETFL ) & O_NONBLOCK ) != O_NONBLOCK ) - { - errno = err; - return( 0 ); - } + int error = errno; - switch( errno = err ) - { + switch ( errno = error ) { #if defined EAGAIN - case EAGAIN: + case EAGAIN: #endif #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: + case EWOULDBLOCK: #endif - return( 1 ); + return ( 1 ); } - return( 0 ); + return ( 0 ); } -#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ /* * Accept a connection from a remote client @@ -316,112 +221,79 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx, int ret; int type; - struct sockaddr_storage client_addr; + struct sockaddr_in client_addr; -#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ - defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) socklen_t n = (socklen_t) sizeof( client_addr ); socklen_t type_len = (socklen_t) sizeof( type ); -#else - int n = (int) sizeof( client_addr ); - int type_len = (int) sizeof( type ); -#endif /* Is this a TCP or UDP socket? */ - if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE, - (void *) &type, &type_len ) != 0 || - ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) - { - return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + if ( lwip_getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE, + (void *) &type, (socklen_t *) &type_len ) != 0 || + ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) { + return ( MBEDTLS_ERR_NET_ACCEPT_FAILED ); } - if( type == SOCK_STREAM ) - { + if ( type == SOCK_STREAM ) { /* TCP: actual accept() */ - ret = client_ctx->fd = (int) accept( bind_ctx->fd, + ret = client_ctx->fd = (int) lwip_accept( bind_ctx->fd, (struct sockaddr *) &client_addr, &n ); - } - else - { + } else { /* UDP: wait for a message, but keep it in the queue */ char buf[1] = { 0 }; - ret = (int) recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK, + ret = lwip_recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK, (struct sockaddr *) &client_addr, &n ); -#if defined(_WIN32) - if( ret == SOCKET_ERROR && - WSAGetLastError() == WSAEMSGSIZE ) - { - /* We know buf is too small, thanks, just peeking here */ - ret = 0; - } -#endif } - if( ret < 0 ) - { - if( net_would_block( bind_ctx ) != 0 ) - return( MBEDTLS_ERR_SSL_WANT_READ ); + if ( ret < 0 ) { + if ( net_would_block( bind_ctx ) != 0 ) { + return ( MBEDTLS_ERR_SSL_WANT_READ ); + } - return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + return ( MBEDTLS_ERR_NET_ACCEPT_FAILED ); } /* UDP: hijack the listening socket to communicate with the client, * then bind a new socket to accept new connections */ - if( type != SOCK_STREAM ) - { - struct sockaddr_storage local_addr; + if ( type != SOCK_STREAM ) { + struct sockaddr_in local_addr; int one = 1; - if( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) - return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + if ( lwip_connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) { + return ( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } client_ctx->fd = bind_ctx->fd; bind_ctx->fd = -1; /* In case we exit early */ - n = sizeof( struct sockaddr_storage ); - if( getsockname( client_ctx->fd, - (struct sockaddr *) &local_addr, &n ) != 0 || - ( bind_ctx->fd = (int) socket( local_addr.ss_family, - SOCK_DGRAM, IPPROTO_UDP ) ) < 0 || - setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR, - (const char *) &one, sizeof( one ) ) != 0 ) - { - return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + n = sizeof( struct sockaddr_in ); + if ( lwip_getsockname( client_ctx->fd, + (struct sockaddr *) &local_addr, &n ) != 0 || + ( bind_ctx->fd = (int) lwip_socket( AF_INET, + SOCK_DGRAM, IPPROTO_UDP ) ) < 0 || + lwip_setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &one, sizeof( one ) ) != 0 ) { + return ( MBEDTLS_ERR_NET_SOCKET_FAILED ); } - if( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) - { - return( MBEDTLS_ERR_NET_BIND_FAILED ); + if ( lwip_bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) { + return ( MBEDTLS_ERR_NET_BIND_FAILED ); } } - if( client_ip != NULL ) - { - if( client_addr.ss_family == AF_INET ) - { - struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; - *ip_len = sizeof( addr4->sin_addr.s_addr ); - - if( buf_size < *ip_len ) - return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + if ( client_ip != NULL ) { + struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; + *ip_len = sizeof( addr4->sin_addr.s_addr ); - memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len ); + if ( buf_size < *ip_len ) { + return ( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); } - else - { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; - *ip_len = sizeof( addr6->sin6_addr.s6_addr ); - if( buf_size < *ip_len ) - return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); - - memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len); - } + memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len ); } - return( 0 ); + return ( 0 ); } /* @@ -429,90 +301,12 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx, */ int mbedtls_net_set_block( mbedtls_net_context *ctx ) { -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - u_long n = 0; - return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); -#else - return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) & ~O_NONBLOCK ) ); -#endif + return ( lwip_fcntl( ctx->fd, F_SETFL, lwip_fcntl( ctx->fd, F_GETFL, 0 ) & ~O_NONBLOCK ) ); } int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ) { -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - u_long n = 1; - return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); -#else - return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) | O_NONBLOCK ) ); -#endif -} - -/* - * Check if data is available on the socket - */ - -int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout ) -{ - int ret; - struct timeval tv; - - fd_set read_fds; - fd_set write_fds; - - int fd = ctx->fd; - - if( fd < 0 ) - return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); - -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) - /* Ensure that memory sanitizers consider read_fds and write_fds as - * initialized even on platforms such as Glibc/x86_64 where FD_ZERO - * is implemented in assembly. */ - memset( &read_fds, 0, sizeof( read_fds ) ); - memset( &write_fds, 0, sizeof( write_fds ) ); -#endif -#endif - - FD_ZERO( &read_fds ); - if( rw & MBEDTLS_NET_POLL_READ ) - { - rw &= ~MBEDTLS_NET_POLL_READ; - FD_SET( fd, &read_fds ); - } - - FD_ZERO( &write_fds ); - if( rw & MBEDTLS_NET_POLL_WRITE ) - { - rw &= ~MBEDTLS_NET_POLL_WRITE; - FD_SET( fd, &write_fds ); - } - - if( rw != 0 ) - return( MBEDTLS_ERR_NET_BAD_INPUT_DATA ); - - tv.tv_sec = timeout / 1000; - tv.tv_usec = ( timeout % 1000 ) * 1000; - - do - { - ret = select( fd + 1, &read_fds, &write_fds, NULL, - timeout == (uint32_t) -1 ? NULL : &tv ); - } - while( IS_EINTR( ret ) ); - - if( ret < 0 ) - return( MBEDTLS_ERR_NET_POLL_FAILED ); - - ret = 0; - if( FD_ISSET( fd, &read_fds ) ) - ret |= MBEDTLS_NET_POLL_READ; - if( FD_ISSET( fd, &write_fds ) ) - ret |= MBEDTLS_NET_POLL_WRITE; - - return( ret ); + return ( lwip_fcntl( ctx->fd, F_SETFL, lwip_fcntl( ctx->fd, F_GETFL, 0 ) | O_NONBLOCK ) ); } /* @@ -520,19 +314,10 @@ int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout ) */ void mbedtls_net_usleep( unsigned long usec ) { -#if defined(_WIN32) - Sleep( ( usec + 999 ) / 1000 ); -#else struct timeval tv; tv.tv_sec = usec / 1000000; -#if defined(__unix__) || defined(__unix) || \ - ( defined(__APPLE__) && defined(__MACH__) ) - tv.tv_usec = (suseconds_t) usec % 1000000; -#else tv.tv_usec = usec % 1000000; -#endif select( 0, NULL, NULL, NULL, &tv ); -#endif } /* @@ -543,47 +328,45 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) int ret; int fd = ((mbedtls_net_context *) ctx)->fd; - if( fd < 0 ) - return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + if ( fd < 0 ) { + return ( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + } - ret = (int) read( fd, buf, len ); + ret = (int) lwip_read( fd, buf, len ); - if( ret < 0 ) - { - if( net_would_block( ctx ) != 0 ) - return( MBEDTLS_ERR_SSL_WANT_READ ); + if ( ret < 0 ) { + if ( net_would_block( ctx ) != 0 ) { + return ( MBEDTLS_ERR_SSL_WANT_READ ); + } -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - if( WSAGetLastError() == WSAECONNRESET ) - return( MBEDTLS_ERR_NET_CONN_RESET ); -#else - if( errno == EPIPE || errno == ECONNRESET ) - return( MBEDTLS_ERR_NET_CONN_RESET ); + if ( errno == EPIPE || errno == ECONNRESET ) { + return ( MBEDTLS_ERR_NET_CONN_RESET ); + } - if( errno == EINTR ) - return( MBEDTLS_ERR_SSL_WANT_READ ); -#endif + if ( errno == EINTR ) { + return ( MBEDTLS_ERR_SSL_WANT_READ ); + } - return( MBEDTLS_ERR_NET_RECV_FAILED ); + return ( MBEDTLS_ERR_NET_RECV_FAILED ); } - return( ret ); + return ( ret ); } /* * Read at most 'len' characters, blocking for at most 'timeout' ms */ -int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, - size_t len, uint32_t timeout ) +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, + uint32_t timeout ) { int ret; struct timeval tv; fd_set read_fds; int fd = ((mbedtls_net_context *) ctx)->fd; - if( fd < 0 ) - return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + if ( fd < 0 ) { + return ( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + } FD_ZERO( &read_fds ); FD_SET( fd, &read_fds ); @@ -591,28 +374,23 @@ int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, tv.tv_sec = timeout / 1000; tv.tv_usec = ( timeout % 1000 ) * 1000; - ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); + ret = lwip_select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); /* Zero fds ready means we timed out */ - if( ret == 0 ) - return( MBEDTLS_ERR_SSL_TIMEOUT ); - - if( ret < 0 ) - { -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - if( WSAGetLastError() == WSAEINTR ) - return( MBEDTLS_ERR_SSL_WANT_READ ); -#else - if( errno == EINTR ) - return( MBEDTLS_ERR_SSL_WANT_READ ); -#endif + if ( ret == 0 ) { + return ( MBEDTLS_ERR_SSL_TIMEOUT ); + } + + if ( ret < 0 ) { + if ( errno == EINTR ) { + return ( MBEDTLS_ERR_SSL_WANT_READ ); + } - return( MBEDTLS_ERR_NET_RECV_FAILED ); + return ( MBEDTLS_ERR_NET_RECV_FAILED ); } /* This call will not block */ - return( mbedtls_net_recv( ctx, buf, len ) ); + return ( mbedtls_net_recv( ctx, buf, len ) ); } /* @@ -623,32 +401,29 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) int ret; int fd = ((mbedtls_net_context *) ctx)->fd; - if( fd < 0 ) - return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + if ( fd < 0 ) { + return ( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + } - ret = (int) write( fd, buf, len ); + ret = (int) lwip_write( fd, buf, len ); - if( ret < 0 ) - { - if( net_would_block( ctx ) != 0 ) - return( MBEDTLS_ERR_SSL_WANT_WRITE ); + if ( ret < 0 ) { + if ( net_would_block( ctx ) != 0 ) { + return ( MBEDTLS_ERR_SSL_WANT_WRITE ); + } -#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ - !defined(EFI32) - if( WSAGetLastError() == WSAECONNRESET ) - return( MBEDTLS_ERR_NET_CONN_RESET ); -#else - if( errno == EPIPE || errno == ECONNRESET ) - return( MBEDTLS_ERR_NET_CONN_RESET ); + if ( errno == EPIPE || errno == ECONNRESET ) { + return ( MBEDTLS_ERR_NET_CONN_RESET ); + } - if( errno == EINTR ) - return( MBEDTLS_ERR_SSL_WANT_WRITE ); -#endif + if ( errno == EINTR ) { + return ( MBEDTLS_ERR_SSL_WANT_WRITE ); + } - return( MBEDTLS_ERR_NET_SEND_FAILED ); + return ( MBEDTLS_ERR_NET_SEND_FAILED ); } - return( ret ); + return ( ret ); } /* @@ -656,10 +431,11 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) */ void mbedtls_net_free( mbedtls_net_context *ctx ) { - if( ctx->fd == -1 ) + if ( ctx->fd == -1 ) { return; + } - shutdown( ctx->fd, 2 ); + lwip_shutdown( ctx->fd, 2 ); close( ctx->fd ); ctx->fd = -1; diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/net_sockets.c.orig b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/net_sockets.c.orig new file mode 100644 index 0000000..816b130 --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/net_sockets.c.orig @@ -0,0 +1,668 @@ +/* + * TCP/IP or UDP/IP networking functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* Enable definition of getaddrinfo() even when compiling with -std=c99. Must + * be set before config.h, which pulls in glibc's features.h indirectly. + * Harmless on other platforms. */ +#define _POSIX_C_SOURCE 200112L + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_NET_C) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ + !defined(__HAIKU__) +#error "This module only works on Unix and Windows, see MBEDTLS_NET_C in config.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#endif + +#include "mbedtls/net_sockets.h" + +#include + +#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ + !defined(EFI32) + +#define IS_EINTR( ret ) ( ( ret ) == WSAEINTR ) + +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501) +#undef _WIN32_WINNT +/* Enables getaddrinfo() & Co */ +#define _WIN32_WINNT 0x0501 +#endif + +#include + +#include +#include + +#if defined(_MSC_VER) +#if defined(_WIN32_WCE) +#pragma comment( lib, "ws2.lib" ) +#else +#pragma comment( lib, "ws2_32.lib" ) +#endif +#endif /* _MSC_VER */ + +#define read(fd,buf,len) recv( fd, (char*)( buf ), (int)( len ), 0 ) +#define write(fd,buf,len) send( fd, (char*)( buf ), (int)( len ), 0 ) +#define close(fd) closesocket(fd) + +static int wsa_init_done = 0; + +#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IS_EINTR( ret ) ( ( ret ) == EINTR ) + +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* Some MS functions want int and MSVC warns if we pass size_t, + * but the standard functions use socklen_t, so cast only for MSVC */ +#if defined(_MSC_VER) +#define MSVC_INT_CAST (int) +#else +#define MSVC_INT_CAST +#endif + +#include + +#include + +#include + +/* + * Prepare for using the sockets interface + */ +static int net_prepare( void ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + WSADATA wsaData; + + if( wsa_init_done == 0 ) + { + if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + + wsa_init_done = 1; + } +#else +#if !defined(EFIX64) && !defined(EFI32) + signal( SIGPIPE, SIG_IGN ); +#endif +#endif + return( 0 ); +} + +/* + * Initialize a context + */ +void mbedtls_net_init( mbedtls_net_context *ctx ) +{ + ctx->fd = -1; +} + +/* + * Initiate a TCP connection with host:port and the given protocol + */ +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, + const char *port, int proto ) +{ + int ret; + struct addrinfo hints, *addr_list, *cur; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + /* Do name resolution with both IPv6 and IPv4 */ + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + + if( getaddrinfo( host, port, &hints, &addr_list ) != 0 ) + return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + + /* Try the sockaddrs until a connection succeeds */ + ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; + for( cur = addr_list; cur != NULL; cur = cur->ai_next ) + { + ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, + cur->ai_protocol ); + if( ctx->fd < 0 ) + { + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + if( connect( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) == 0 ) + { + ret = 0; + break; + } + + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_CONNECT_FAILED; + } + + freeaddrinfo( addr_list ); + + return( ret ); +} + +/* + * Create a listening socket on bind_ip:port + */ +int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ) +{ + int n, ret; + struct addrinfo hints, *addr_list, *cur; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + /* Bind to IPv6 and/or IPv4, but only in the desired protocol */ + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + if( bind_ip == NULL ) + hints.ai_flags = AI_PASSIVE; + + if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) + return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + + /* Try the sockaddrs until a binding succeeds */ + ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; + for( cur = addr_list; cur != NULL; cur = cur->ai_next ) + { + ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, + cur->ai_protocol ); + if( ctx->fd < 0 ) + { + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + n = 1; + if( setsockopt( ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &n, sizeof( n ) ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + if( bind( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_BIND_FAILED; + continue; + } + + /* Listen only makes sense for TCP */ + if( proto == MBEDTLS_NET_PROTO_TCP ) + { + if( listen( ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_LISTEN_FAILED; + continue; + } + } + + /* Bind was successful */ + ret = 0; + break; + } + + freeaddrinfo( addr_list ); + + return( ret ); + +} + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + ((void) ctx); + return( WSAGetLastError() == WSAEWOULDBLOCK ); +} +#else +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + * + * Note: on a blocking socket this function always returns 0! + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + int err = errno; + + /* + * Never return 'WOULD BLOCK' on a non-blocking socket + */ + if( ( fcntl( ctx->fd, F_GETFL ) & O_NONBLOCK ) != O_NONBLOCK ) + { + errno = err; + return( 0 ); + } + + switch( errno = err ) + { +#if defined EAGAIN + case EAGAIN: +#endif +#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + return( 1 ); + } + return( 0 ); +} +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* + * Accept a connection from a remote client + */ +int mbedtls_net_accept( mbedtls_net_context *bind_ctx, + mbedtls_net_context *client_ctx, + void *client_ip, size_t buf_size, size_t *ip_len ) +{ + int ret; + int type; + + struct sockaddr_storage client_addr; + +#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ + defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) + socklen_t n = (socklen_t) sizeof( client_addr ); + socklen_t type_len = (socklen_t) sizeof( type ); +#else + int n = (int) sizeof( client_addr ); + int type_len = (int) sizeof( type ); +#endif + + /* Is this a TCP or UDP socket? */ + if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE, + (void *) &type, &type_len ) != 0 || + ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) + { + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } + + if( type == SOCK_STREAM ) + { + /* TCP: actual accept() */ + ret = client_ctx->fd = (int) accept( bind_ctx->fd, + (struct sockaddr *) &client_addr, &n ); + } + else + { + /* UDP: wait for a message, but keep it in the queue */ + char buf[1] = { 0 }; + + ret = (int) recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK, + (struct sockaddr *) &client_addr, &n ); + +#if defined(_WIN32) + if( ret == SOCKET_ERROR && + WSAGetLastError() == WSAEMSGSIZE ) + { + /* We know buf is too small, thanks, just peeking here */ + ret = 0; + } +#endif + } + + if( ret < 0 ) + { + if( net_would_block( bind_ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } + + /* UDP: hijack the listening socket to communicate with the client, + * then bind a new socket to accept new connections */ + if( type != SOCK_STREAM ) + { + struct sockaddr_storage local_addr; + int one = 1; + + if( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + + client_ctx->fd = bind_ctx->fd; + bind_ctx->fd = -1; /* In case we exit early */ + + n = sizeof( struct sockaddr_storage ); + if( getsockname( client_ctx->fd, + (struct sockaddr *) &local_addr, &n ) != 0 || + ( bind_ctx->fd = (int) socket( local_addr.ss_family, + SOCK_DGRAM, IPPROTO_UDP ) ) < 0 || + setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &one, sizeof( one ) ) != 0 ) + { + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + } + + if( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) + { + return( MBEDTLS_ERR_NET_BIND_FAILED ); + } + } + + if( client_ip != NULL ) + { + if( client_addr.ss_family == AF_INET ) + { + struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; + *ip_len = sizeof( addr4->sin_addr.s_addr ); + + if( buf_size < *ip_len ) + return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + + memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len ); + } + else + { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; + *ip_len = sizeof( addr6->sin6_addr.s6_addr ); + + if( buf_size < *ip_len ) + return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + + memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len); + } + } + + return( 0 ); +} + +/* + * Set the socket blocking or non-blocking + */ +int mbedtls_net_set_block( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 0; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) & ~O_NONBLOCK ) ); +#endif +} + +int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 1; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) | O_NONBLOCK ) ); +#endif +} + +/* + * Check if data is available on the socket + */ + +int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout ) +{ + int ret; + struct timeval tv; + + fd_set read_fds; + fd_set write_fds; + + int fd = ctx->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + /* Ensure that memory sanitizers consider read_fds and write_fds as + * initialized even on platforms such as Glibc/x86_64 where FD_ZERO + * is implemented in assembly. */ + memset( &read_fds, 0, sizeof( read_fds ) ); + memset( &write_fds, 0, sizeof( write_fds ) ); +#endif +#endif + + FD_ZERO( &read_fds ); + if( rw & MBEDTLS_NET_POLL_READ ) + { + rw &= ~MBEDTLS_NET_POLL_READ; + FD_SET( fd, &read_fds ); + } + + FD_ZERO( &write_fds ); + if( rw & MBEDTLS_NET_POLL_WRITE ) + { + rw &= ~MBEDTLS_NET_POLL_WRITE; + FD_SET( fd, &write_fds ); + } + + if( rw != 0 ) + return( MBEDTLS_ERR_NET_BAD_INPUT_DATA ); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + do + { + ret = select( fd + 1, &read_fds, &write_fds, NULL, + timeout == (uint32_t) -1 ? NULL : &tv ); + } + while( IS_EINTR( ret ) ); + + if( ret < 0 ) + return( MBEDTLS_ERR_NET_POLL_FAILED ); + + ret = 0; + if( FD_ISSET( fd, &read_fds ) ) + ret |= MBEDTLS_NET_POLL_READ; + if( FD_ISSET( fd, &write_fds ) ) + ret |= MBEDTLS_NET_POLL_WRITE; + + return( ret ); +} + +/* + * Portable usleep helper + */ +void mbedtls_net_usleep( unsigned long usec ) +{ +#if defined(_WIN32) + Sleep( ( usec + 999 ) / 1000 ); +#else + struct timeval tv; + tv.tv_sec = usec / 1000000; +#if defined(__unix__) || defined(__unix) || \ + ( defined(__APPLE__) && defined(__MACH__) ) + tv.tv_usec = (suseconds_t) usec % 1000000; +#else + tv.tv_usec = usec % 1000000; +#endif + select( 0, NULL, NULL, NULL, &tv ); +#endif +} + +/* + * Read at most 'len' characters + */ +int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + ret = (int) read( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + + return( ret ); +} + +/* + * Read at most 'len' characters, blocking for at most 'timeout' ms + */ +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, + size_t len, uint32_t timeout ) +{ + int ret; + struct timeval tv; + fd_set read_fds; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + FD_ZERO( &read_fds ); + FD_SET( fd, &read_fds ); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); + + /* Zero fds ready means we timed out */ + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_TIMEOUT ); + + if( ret < 0 ) + { +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAEINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#else + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + + /* This call will not block */ + return( mbedtls_net_recv( ctx, buf, len ) ); +} + +/* + * Write at most 'len' characters + */ +int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + ret = (int) write( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); +#endif + + return( MBEDTLS_ERR_NET_SEND_FAILED ); + } + + return( ret ); +} + +/* + * Gracefully close the connection + */ +void mbedtls_net_free( mbedtls_net_context *ctx ) +{ + if( ctx->fd == -1 ) + return; + + shutdown( ctx->fd, 2 ); + close( ctx->fd ); + + ctx->fd = -1; +} + +#endif /* MBEDTLS_NET_C */ diff --git a/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/poly1305.c b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/poly1305.c new file mode 100644 index 0000000..2b56c5f --- /dev/null +++ b/k210-freertos/platform/sdk/kendryte-freertos-sdk/third_party/mbedtls/library/poly1305.c @@ -0,0 +1,559 @@ +/** + * \file poly1305.c + * + * \brief Poly1305 authentication algorithm. + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_POLY1305_C) + +#include "mbedtls/poly1305.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_POLY1305_ALT) + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Parameter validation macros */ +#define POLY1305_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA ) +#define POLY1305_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define POLY1305_BLOCK_SIZE_BYTES ( 16U ) + +#define BYTES_TO_U32_LE( data, offset ) \ + ( (uint32_t) (data)[offset] \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \ + ) + +/* + * Our implementation is tuned for 32-bit platforms with a 64-bit multiplier. + * However we provided an alternative for platforms without such a multiplier. + */ +#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION) +static uint64_t mul64( uint32_t a, uint32_t b ) +{ + /* a = al + 2**16 ah, b = bl + 2**16 bh */ + const uint16_t al = (uint16_t) a; + const uint16_t bl = (uint16_t) b; + const uint16_t ah = a >> 16; + const uint16_t bh = b >> 16; + + /* ab = al*bl + 2**16 (ah*bl + bl*bh) + 2**32 ah*bh */ + const uint32_t lo = (uint32_t) al * bl; + const uint64_t me = (uint64_t)( (uint32_t) ah * bl ) + (uint32_t) al * bh; + const uint32_t hi = (uint32_t) ah * bh; + + return( lo + ( me << 16 ) + ( (uint64_t) hi << 32 ) ); +} +#else +static inline uint64_t mul64( uint32_t a, uint32_t b ) +{ + return( (uint64_t) a * b ); +} +#endif + + +/** + * \brief Process blocks with Poly1305. + * + * \param ctx The Poly1305 context. + * \param nblocks Number of blocks to process. Note that this + * function only processes full blocks. + * \param input Buffer containing the input block(s). + * \param needs_padding Set to 0 if the padding bit has already been + * applied to the input data before calling this + * function. Otherwise, set this parameter to 1. + */ +static void poly1305_process( mbedtls_poly1305_context *ctx, + size_t nblocks, + const unsigned char *input, + uint32_t needs_padding ) +{ + uint64_t d0, d1, d2, d3; + uint32_t acc0, acc1, acc2, acc3, acc4; + uint32_t r0, r1, r2, r3; + uint32_t rs1, rs2, rs3; + size_t offset = 0U; + size_t i; + + r0 = ctx->r[0]; + r1 = ctx->r[1]; + r2 = ctx->r[2]; + r3 = ctx->r[3]; + + rs1 = r1 + ( r1 >> 2U ); + rs2 = r2 + ( r2 >> 2U ); + rs3 = r3 + ( r3 >> 2U ); + + acc0 = ctx->acc[0]; + acc1 = ctx->acc[1]; + acc2 = ctx->acc[2]; + acc3 = ctx->acc[3]; + acc4 = ctx->acc[4]; + + /* Process full blocks */ + for( i = 0U; i < nblocks; i++ ) + { + /* The input block is treated as a 128-bit little-endian integer */ + d0 = BYTES_TO_U32_LE( input, offset + 0 ); + d1 = BYTES_TO_U32_LE( input, offset + 4 ); + d2 = BYTES_TO_U32_LE( input, offset + 8 ); + d3 = BYTES_TO_U32_LE( input, offset + 12 ); + + /* Compute: acc += (padded) block as a 130-bit integer */ + d0 += (uint64_t) acc0; + d1 += (uint64_t) acc1 + ( d0 >> 32U ); + d2 += (uint64_t) acc2 + ( d1 >> 32U ); + d3 += (uint64_t) acc3 + ( d2 >> 32U ); + acc0 = (uint32_t) d0; + acc1 = (uint32_t) d1; + acc2 = (uint32_t) d2; + acc3 = (uint32_t) d3; + acc4 += (uint32_t) ( d3 >> 32U ) + needs_padding; + + /* Compute: acc *= r */ + d0 = mul64( acc0, r0 ) + + mul64( acc1, rs3 ) + + mul64( acc2, rs2 ) + + mul64( acc3, rs1 ); + d1 = mul64( acc0, r1 ) + + mul64( acc1, r0 ) + + mul64( acc2, rs3 ) + + mul64( acc3, rs2 ) + + mul64( acc4, rs1 ); + d2 = mul64( acc0, r2 ) + + mul64( acc1, r1 ) + + mul64( acc2, r0 ) + + mul64( acc3, rs3 ) + + mul64( acc4, rs2 ); + d3 = mul64( acc0, r3 ) + + mul64( acc1, r2 ) + + mul64( acc2, r1 ) + + mul64( acc3, r0 ) + + mul64( acc4, rs3 ); + acc4 *= r0; + + /* Compute: acc %= (2^130 - 5) (partial remainder) */ + d1 += ( d0 >> 32 ); + d2 += ( d1 >> 32 ); + d3 += ( d2 >> 32 ); + acc0 = (uint32_t) d0; + acc1 = (uint32_t) d1; + acc2 = (uint32_t) d2; + acc3 = (uint32_t) d3; + acc4 = (uint32_t) ( d3 >> 32 ) + acc4; + + d0 = (uint64_t) acc0 + ( acc4 >> 2 ) + ( acc4 & 0xFFFFFFFCU ); + acc4 &= 3U; + acc0 = (uint32_t) d0; + d0 = (uint64_t) acc1 + ( d0 >> 32U ); + acc1 = (uint32_t) d0; + d0 = (uint64_t) acc2 + ( d0 >> 32U ); + acc2 = (uint32_t) d0; + d0 = (uint64_t) acc3 + ( d0 >> 32U ); + acc3 = (uint32_t) d0; + d0 = (uint64_t) acc4 + ( d0 >> 32U ); + acc4 = (uint32_t) d0; + + offset += POLY1305_BLOCK_SIZE_BYTES; + } + + ctx->acc[0] = acc0; + ctx->acc[1] = acc1; + ctx->acc[2] = acc2; + ctx->acc[3] = acc3; + ctx->acc[4] = acc4; +} + +/** + * \brief Compute the Poly1305 MAC + * + * \param ctx The Poly1305 context. + * \param mac The buffer to where the MAC is written. Must be + * big enough to contain the 16-byte MAC. + */ +static void poly1305_compute_mac( const mbedtls_poly1305_context *ctx, + unsigned char mac[16] ) +{ + uint64_t d; + uint32_t g0, g1, g2, g3, g4; + uint32_t acc0, acc1, acc2, acc3, acc4; + uint32_t mask; + uint32_t mask_inv; + + acc0 = ctx->acc[0]; + acc1 = ctx->acc[1]; + acc2 = ctx->acc[2]; + acc3 = ctx->acc[3]; + acc4 = ctx->acc[4]; + + /* Before adding 's' we ensure that the accumulator is mod 2^130 - 5. + * We do this by calculating acc - (2^130 - 5), then checking if + * the 131st bit is set. If it is, then reduce: acc -= (2^130 - 5) + */ + + /* Calculate acc + -(2^130 - 5) */ + d = ( (uint64_t) acc0 + 5U ); + g0 = (uint32_t) d; + d = ( (uint64_t) acc1 + ( d >> 32 ) ); + g1 = (uint32_t) d; + d = ( (uint64_t) acc2 + ( d >> 32 ) ); + g2 = (uint32_t) d; + d = ( (uint64_t) acc3 + ( d >> 32 ) ); + g3 = (uint32_t) d; + g4 = acc4 + (uint32_t) ( d >> 32U ); + + /* mask == 0xFFFFFFFF if 131st bit is set, otherwise mask == 0 */ + mask = (uint32_t) 0U - ( g4 >> 2U ); + mask_inv = ~mask; + + /* If 131st bit is set then acc=g, otherwise, acc is unmodified */ + acc0 = ( acc0 & mask_inv ) | ( g0 & mask ); + acc1 = ( acc1 & mask_inv ) | ( g1 & mask ); + acc2 = ( acc2 & mask_inv ) | ( g2 & mask ); + acc3 = ( acc3 & mask_inv ) | ( g3 & mask ); + + /* Add 's' */ + d = (uint64_t) acc0 + ctx->s[0]; + acc0 = (uint32_t) d; + d = (uint64_t) acc1 + ctx->s[1] + ( d >> 32U ); + acc1 = (uint32_t) d; + d = (uint64_t) acc2 + ctx->s[2] + ( d >> 32U ); + acc2 = (uint32_t) d; + acc3 += ctx->s[3] + (uint32_t) ( d >> 32U ); + + /* Compute MAC (128 least significant bits of the accumulator) */ + mac[ 0] = (unsigned char)( acc0 ); + mac[ 1] = (unsigned char)( acc0 >> 8 ); + mac[ 2] = (unsigned char)( acc0 >> 16 ); + mac[ 3] = (unsigned char)( acc0 >> 24 ); + mac[ 4] = (unsigned char)( acc1 ); + mac[ 5] = (unsigned char)( acc1 >> 8 ); + mac[ 6] = (unsigned char)( acc1 >> 16 ); + mac[ 7] = (unsigned char)( acc1 >> 24 ); + mac[ 8] = (unsigned char)( acc2 ); + mac[ 9] = (unsigned char)( acc2 >> 8 ); + mac[10] = (unsigned char)( acc2 >> 16 ); + mac[11] = (unsigned char)( acc2 >> 24 ); + mac[12] = (unsigned char)( acc3 ); + mac[13] = (unsigned char)( acc3 >> 8 ); + mac[14] = (unsigned char)( acc3 >> 16 ); + mac[15] = (unsigned char)( acc3 >> 24 ); +} + +void mbedtls_poly1305_init( mbedtls_poly1305_context *ctx ) +{ + POLY1305_VALIDATE( ctx != NULL ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_poly1305_context ) ); +} + +void mbedtls_poly1305_free( mbedtls_poly1305_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_poly1305_context ) ); +} + +int mbedtls_poly1305_starts( mbedtls_poly1305_context *ctx, + const unsigned char key[32] ) +{ + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( key != NULL ); + + /* r &= 0x0ffffffc0ffffffc0ffffffc0fffffff */ + ctx->r[0] = BYTES_TO_U32_LE( key, 0 ) & 0x0FFFFFFFU; + ctx->r[1] = BYTES_TO_U32_LE( key, 4 ) & 0x0FFFFFFCU; + ctx->r[2] = BYTES_TO_U32_LE( key, 8 ) & 0x0FFFFFFCU; + ctx->r[3] = BYTES_TO_U32_LE( key, 12 ) & 0x0FFFFFFCU; + + ctx->s[0] = BYTES_TO_U32_LE( key, 16 ); + ctx->s[1] = BYTES_TO_U32_LE( key, 20 ); + ctx->s[2] = BYTES_TO_U32_LE( key, 24 ); + ctx->s[3] = BYTES_TO_U32_LE( key, 28 ); + + /* Initial accumulator state */ + ctx->acc[0] = 0U; + ctx->acc[1] = 0U; + ctx->acc[2] = 0U; + ctx->acc[3] = 0U; + ctx->acc[4] = 0U; + + /* Queue initially empty */ + mbedtls_platform_zeroize( ctx->queue, sizeof( ctx->queue ) ); + ctx->queue_len = 0U; + + return( 0 ); +} + +int mbedtls_poly1305_update( mbedtls_poly1305_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + size_t offset = 0U; + size_t remaining = ilen; + size_t queue_free_len; + size_t nblocks; + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( ilen == 0 || input != NULL ); + + if( ( remaining > 0U ) && ( ctx->queue_len > 0U ) ) + { + queue_free_len = ( POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len ); + + if( ilen < queue_free_len ) + { + /* Not enough data to complete the block. + * Store this data with the other leftovers. + */ + memcpy( &ctx->queue[ctx->queue_len], + input, + ilen ); + + ctx->queue_len += ilen; + + remaining = 0U; + } + else + { + /* Enough data to produce a complete block */ + memcpy( &ctx->queue[ctx->queue_len], + input, + queue_free_len ); + + ctx->queue_len = 0U; + + poly1305_process( ctx, 1U, ctx->queue, 1U ); /* add padding bit */ + + offset += queue_free_len; + remaining -= queue_free_len; + } + } + + if( remaining >= POLY1305_BLOCK_SIZE_BYTES ) + { + nblocks = remaining / POLY1305_BLOCK_SIZE_BYTES; + + poly1305_process( ctx, nblocks, &input[offset], 1U ); + + offset += nblocks * POLY1305_BLOCK_SIZE_BYTES; + remaining %= POLY1305_BLOCK_SIZE_BYTES; + } + + if( remaining > 0U ) + { + /* Store partial block */ + ctx->queue_len = remaining; + memcpy( ctx->queue, &input[offset], remaining ); + } + + return( 0 ); +} + +int mbedtls_poly1305_finish( mbedtls_poly1305_context *ctx, + unsigned char mac[16] ) +{ + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( mac != NULL ); + + /* Process any leftover data */ + if( ctx->queue_len > 0U ) + { + /* Add padding bit */ + ctx->queue[ctx->queue_len] = 1U; + ctx->queue_len++; + + /* Pad with zeroes */ + memset( &ctx->queue[ctx->queue_len], + 0, + POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len ); + + poly1305_process( ctx, 1U, /* Process 1 block */ + ctx->queue, 0U ); /* Already padded above */ + } + + poly1305_compute_mac( ctx, mac ); + + return( 0 ); +} + +int mbedtls_poly1305_mac( const unsigned char key[32], + const unsigned char *input, + size_t ilen, + unsigned char mac[16] ) +{ + mbedtls_poly1305_context ctx; + int ret; + POLY1305_VALIDATE_RET( key != NULL ); + POLY1305_VALIDATE_RET( mac != NULL ); + POLY1305_VALIDATE_RET( ilen == 0 || input != NULL ); + + mbedtls_poly1305_init( &ctx ); + + ret = mbedtls_poly1305_starts( &ctx, key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_update( &ctx, input, ilen ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_finish( &ctx, mac ); + +cleanup: + mbedtls_poly1305_free( &ctx ); + return( ret ); +} + +#endif /* MBEDTLS_POLY1305_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_keys[2][32] = +{ + { + 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, + 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, + 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, + 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b + }, + { + 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, + 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, + 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, + 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 + } +}; + +static const unsigned char test_data[2][127] = +{ + { + 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x6f, + 0x72, 0x75, 0x6d, 0x20, 0x52, 0x65, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6f, + 0x75, 0x70 + }, + { + 0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72, + 0x69, 0x6c, 0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x6c, 0x69, 0x74, 0x68, 0x79, 0x20, 0x74, 0x6f, + 0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20, + 0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x67, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41, 0x6c, 0x6c, + 0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x6f, 0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65, + 0x73, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d, 0x65, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75, + 0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e + } +}; + +static const size_t test_data_len[2] = +{ + 34U, + 127U +}; + +static const unsigned char test_mac[2][16] = +{ + { + 0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6, + 0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9 + }, + { + 0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61, + 0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62 + } +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_poly1305_self_test( int verbose ) +{ + unsigned char mac[16]; + unsigned i; + int ret; + + for( i = 0U; i < 2U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " Poly1305 test %u ", i ); + + ret = mbedtls_poly1305_mac( test_keys[i], + test_data[i], + test_data_len[i], + mac ); + ASSERT( 0 == ret, ( "error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( mac, test_mac[i], 16U ), ( "failed (mac)\n" ) ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_POLY1305_C */ diff --git a/micropython/py/obj.h b/micropython/py/obj.h index b832ab9..50e2325 100644 --- a/micropython/py/obj.h +++ b/micropython/py/obj.h @@ -289,6 +289,24 @@ typedef mp_const_obj_t mp_rom_obj_t; // Macros to create objects that are stored in ROM. +#ifndef MP_ROM_NONE +#if MICROPY_OBJ_IMMEDIATE_OBJS +#define MP_ROM_NONE mp_const_none +#else +#define MP_ROM_NONE MP_ROM_PTR(&mp_const_none_obj) +#endif +#endif + +#ifndef MP_ROM_FALSE +#if MICROPY_OBJ_IMMEDIATE_OBJS +#define MP_ROM_FALSE mp_const_false +#define MP_ROM_TRUE mp_const_true +#else +#define MP_ROM_FALSE MP_ROM_PTR(&mp_const_false_obj) +#define MP_ROM_TRUE MP_ROM_PTR(&mp_const_true_obj) +#endif +#endif + #ifndef MP_ROM_INT typedef mp_const_obj_t mp_rom_obj_t; #define MP_ROM_INT(i) MP_OBJ_NEW_SMALL_INT(i) @@ -706,6 +724,10 @@ mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg); mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args); mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg); mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) +#ifdef va_start +mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const char *fmt, va_list arg); // same fmt restrictions as above +#endif +mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_native(mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data, const mp_uint_t *const_table); mp_obj_t mp_obj_new_fun_asm(size_t n_args, const void *fun_data, mp_uint_t type_sig); @@ -830,8 +852,21 @@ static inline mp_map_t *mp_obj_dict_get_map(mp_obj_t dict) { // set void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item); +// slice indexes resolved to particular sequence +typedef struct { + mp_int_t start; + mp_int_t stop; + mp_int_t step; +} mp_bound_slice_t; + // slice -void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step); +typedef struct _mp_obj_slice_t { + mp_obj_base_t base; + mp_obj_t start; + mp_obj_t stop; + mp_obj_t step; +} mp_obj_slice_t; +void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result); // functions @@ -888,13 +923,6 @@ const mp_obj_t *mp_obj_property_get(mp_obj_t self_in); // sequence helpers -// slice indexes resolved to particular sequence -typedef struct { - mp_uint_t start; - mp_uint_t stop; - mp_int_t step; -} mp_bound_slice_t; - void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times, void *dest); #if MICROPY_PY_BUILTINS_SLICE bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes); diff --git a/micropython/py/objexcept.c b/micropython/py/objexcept.c index dadbe98..8c4c423 100644 --- a/micropython/py/objexcept.c +++ b/micropython/py/objexcept.c @@ -385,6 +385,14 @@ STATIC void exc_add_strn(void *data, const char *str, size_t len) { } mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + mp_obj_t exc = mp_obj_new_exception_msg_vlist(exc_type, fmt, args); + va_end(args); + return exc; +} + +mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const char *fmt, va_list args) { assert(fmt != NULL); // Check that the given type is an exception type @@ -403,10 +411,10 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char if ((o_str == NULL || o_str_buf == NULL) && mp_emergency_exception_buf_size >= EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t) + 16) { used_emg_buf = true; - o_str = (mp_obj_str_t*)((uint8_t*)MP_STATE_VM(mp_emergency_exception_buf) + o_str = (mp_obj_str_t *)((uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + EMG_BUF_STR_OFFSET); - o_str_buf = (byte*)&o_str[1]; - o_str_alloc = (uint8_t*)MP_STATE_VM(mp_emergency_exception_buf) + o_str_buf = (byte *)&o_str[1]; + o_str_alloc = (uint8_t *)MP_STATE_VM(mp_emergency_exception_buf) + mp_emergency_exception_buf_size - o_str_buf; } #endif @@ -420,15 +428,12 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char // No memory for the string buffer: assume that the fmt string is in ROM // and use that data as the data of the string o_str->len = o_str_alloc - 1; // will be equal to strlen(fmt) - o_str->data = (const byte*)fmt; + o_str->data = (const byte *)fmt; } else { // We have some memory to format the string struct _exc_printer_t exc_pr = {!used_emg_buf, o_str_alloc, 0, o_str_buf}; mp_print_t print = {&exc_pr, exc_add_strn}; - va_list ap; - va_start(ap, fmt); - mp_vprintf(&print, fmt, ap); - va_end(ap); + mp_vprintf(&print, fmt, args); exc_pr.buf[exc_pr.len] = '\0'; o_str->len = exc_pr.len; o_str->data = exc_pr.buf; diff --git a/micropython/py/objslice.c b/micropython/py/objslice.c index cfc819e..d1c23cb 100644 --- a/micropython/py/objslice.c +++ b/micropython/py/objslice.c @@ -27,20 +27,13 @@ #include #include -#include "py/obj.h" +#include "py/runtime.h" /******************************************************************************/ /* slice object */ #if MICROPY_PY_BUILTINS_SLICE -typedef struct _mp_obj_slice_t { - mp_obj_base_t base; - mp_obj_t start; - mp_obj_t stop; - mp_obj_t step; -} mp_obj_slice_t; - STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_slice_t *o = MP_OBJ_TO_PTR(o_in); @@ -53,6 +46,22 @@ STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t mp_print_str(print, ")"); } +#if MICROPY_PY_BUILTINS_SLICE_INDICES +STATIC mp_obj_t slice_indices(mp_obj_t self_in, mp_obj_t length_obj) { + mp_int_t length = mp_obj_int_get_checked(length_obj); + mp_bound_slice_t bound_indices; + mp_obj_slice_indices(self_in, length, &bound_indices); + + mp_obj_t results[3] = { + MP_OBJ_NEW_SMALL_INT(bound_indices.start), + MP_OBJ_NEW_SMALL_INT(bound_indices.stop), + MP_OBJ_NEW_SMALL_INT(bound_indices.step), + }; + return mp_obj_new_tuple(3, results); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(slice_indices_obj, slice_indices); +#endif + #if MICROPY_PY_BUILTINS_SLICE_ATTRS STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { @@ -60,23 +69,38 @@ STATIC void slice_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { return; } mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); + if (attr == MP_QSTR_start) { dest[0] = self->start; } else if (attr == MP_QSTR_stop) { dest[0] = self->stop; } else if (attr == MP_QSTR_step) { dest[0] = self->step; + #if MICROPY_PY_BUILTINS_SLICE_INDICES + } else if (attr == MP_QSTR_indices) { + dest[0] = MP_OBJ_FROM_PTR(&slice_indices_obj); + dest[1] = self_in; + #endif } } #endif +#if MICROPY_PY_BUILTINS_SLICE_INDICES && !MICROPY_PY_BUILTINS_SLICE_ATTRS +STATIC const mp_rom_map_elem_t slice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_indices), MP_ROM_PTR(&slice_indices_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(slice_locals_dict, slice_locals_dict_table); +#endif + const mp_obj_type_t mp_type_slice = { { &mp_type_type }, .name = MP_QSTR_slice, .print = slice_print, -#if MICROPY_PY_BUILTINS_SLICE_ATTRS + #if MICROPY_PY_BUILTINS_SLICE_ATTRS .attr = slice_attr, -#endif + #elif MICROPY_PY_BUILTINS_SLICE_INDICES + .locals_dict = (mp_obj_dict_t *)&slice_locals_dict, + #endif }; mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { @@ -88,12 +112,69 @@ mp_obj_t mp_obj_new_slice(mp_obj_t ostart, mp_obj_t ostop, mp_obj_t ostep) { return MP_OBJ_FROM_PTR(o); } -void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step) { - assert(mp_obj_is_type(self_in, &mp_type_slice)); +// Return the real index and step values for a slice when applied to a sequence of +// the given length, resolving missing components, negative values and values off +// the end of the sequence. +void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result) { mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); - *start = self->start; - *stop = self->stop; - *step = self->step; + mp_int_t start, stop, step; + + if (self->step == mp_const_none) { + step = 1; + } else { + step = mp_obj_get_int(self->step); + if (step == 0) { + mp_raise_ValueError("slice step cannot be zero"); + } + } + + if (step > 0) { + // Positive step + if (self->start == mp_const_none) { + start = 0; + } else { + start = mp_obj_get_int(self->start); + if (start < 0) { + start += length; + } + start = MIN(length, MAX(start, 0)); + } + + if (self->stop == mp_const_none) { + stop = length; + } else { + stop = mp_obj_get_int(self->stop); + if (stop < 0) { + stop += length; + } + stop = MIN(length, MAX(stop, 0)); + } + } else { + // Negative step + if (self->start == mp_const_none) { + start = length - 1; + } else { + start = mp_obj_get_int(self->start); + if (start < 0) { + start += length; + } + start = MIN(length - 1, MAX(start, -1)); + } + + if (self->stop == mp_const_none) { + stop = -1; + } else { + stop = mp_obj_get_int(self->stop); + if (stop < 0) { + stop += length; + } + stop = MIN(length - 1, MAX(stop, -1)); + } + } + + result->start = start; + result->stop = stop; + result->step = step; } #endif diff --git a/micropython/py/objstrunicode.c b/micropython/py/objstrunicode.c index 78d0b50..defcbe4 100644 --- a/micropython/py/objstrunicode.c +++ b/micropython/py/objstrunicode.c @@ -113,7 +113,7 @@ STATIC mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) { // Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or // be capped to the first/last character of the string, depending on is_slice. const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len, - mp_obj_t index, bool is_slice) { + mp_obj_t index, bool is_slice) { // All str functions also handle bytes objects, and they call str_index_to_ptr(), // so it must handle bytes. if (type == &mp_type_bytes) { @@ -129,11 +129,10 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s if (mp_obj_is_small_int(index)) { i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index))); + mp_raise_msg_varg(&mp_type_TypeError, "string indices must be integers, not %s", mp_obj_get_type_str(index)); } const byte *s, *top = self_data + self_len; - if (i < 0) - { + if (i < 0) { // Negative indexing is performed by counting from the end of the string. for (s = top - 1; i; --s) { if (s < self_data) { @@ -176,15 +175,19 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s } STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_obj_type_t *type = mp_obj_get_type(self_in); assert(type == &mp_type_str); GET_STR_DATA_LEN(self_in, self_data, self_len); if (value == MP_OBJ_SENTINEL) { // load -#if MICROPY_PY_BUILTINS_SLICE + #if MICROPY_PY_BUILTINS_SLICE if (mp_obj_is_type(index, &mp_type_slice)) { mp_obj_t ostart, ostop, ostep; - mp_obj_slice_get(index, &ostart, &ostop, &ostep); + mp_obj_slice_t *slice = MP_OBJ_TO_PTR(index); + ostart = slice->start; + ostop = slice->stop; + ostep = slice->step; + if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { mp_raise_NotImplementedError("only slices with step=1 (aka None) are supported"); } @@ -207,7 +210,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart); } -#endif + #endif const byte *s = str_index_to_ptr(type, self_data, self_len, index, false); int len = 1; if (UTF8_IS_NONASCII(*s)) { @@ -216,16 +219,16 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { ++len; } } - return mp_obj_new_str_via_qstr((const char*)s, len); // This will create a one-character string + return mp_obj_new_str_via_qstr((const char *)s, len); // This will create a one-character string } else { return MP_OBJ_NULL; // op not supported } } STATIC const mp_rom_map_elem_t struni_locals_dict_table[] = { -#if MICROPY_CPYTHON_COMPAT + #if MICROPY_CPYTHON_COMPAT { MP_ROM_QSTR(MP_QSTR_encode), MP_ROM_PTR(&str_encode_obj) }, -#endif + #endif { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&str_find_obj) }, { MP_ROM_QSTR(MP_QSTR_rfind), MP_ROM_PTR(&str_rfind_obj) }, { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&str_index_obj) }, @@ -274,7 +277,7 @@ const mp_obj_type_t mp_type_str = { .subscr = str_subscr, .getiter = mp_obj_new_str_iterator, .buffer_p = { .get_buffer = mp_obj_str_get_buffer }, - .locals_dict = (mp_obj_dict_t*)&struni_locals_dict, + .locals_dict = (mp_obj_dict_t *)&struni_locals_dict, }; /******************************************************************************/ @@ -293,7 +296,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { if (self->cur < len) { const byte *cur = str + self->cur; const byte *end = utf8_next_char(str + self->cur); - mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)cur, end - cur); + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char *)cur, end - cur); self->cur += end - cur; return o_out; } else { @@ -303,7 +306,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) { assert(sizeof(mp_obj_str_it_t) <= sizeof(mp_obj_iter_buf_t)); - mp_obj_str_it_t *o = (mp_obj_str_it_t*)iter_buf; + mp_obj_str_it_t *o = (mp_obj_str_it_t *)iter_buf; o->base.type = &mp_type_polymorph_iter; o->iternext = str_it_iternext; o->str = str; diff --git a/micropython/py/runtime.c b/micropython/py/runtime.c index 9436e66..809c593 100644 --- a/micropython/py/runtime.c +++ b/micropython/py/runtime.c @@ -26,6 +26,7 @@ * THE SOFTWARE. */ +#include #include #include #include @@ -1507,6 +1508,14 @@ NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg) { } } +NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + mp_obj_t exc = mp_obj_new_exception_msg_vlist(exc_type, fmt, args); + va_end(args); + nlr_raise(exc); +} + NORETURN void mp_raise_ValueError(const char *msg) { mp_raise_msg(&mp_type_ValueError, msg); } diff --git a/micropython/py/runtime.h b/micropython/py/runtime.h index b54b17b..53cbbf3 100644 --- a/micropython/py/runtime.h +++ b/micropython/py/runtime.h @@ -151,6 +151,7 @@ mp_obj_t mp_import_from(mp_obj_t module, qstr name); void mp_import_all(mp_obj_t module); NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg); +NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); NORETURN void mp_raise_ValueError(const char *msg); NORETURN void mp_raise_TypeError(const char *msg); NORETURN void mp_raise_NotImplementedError(const char *msg); diff --git a/micropython/py/sequence.c b/micropython/py/sequence.c index 4c19fc6..c9cb041 100644 --- a/micropython/py/sequence.c +++ b/micropython/py/sequence.c @@ -39,85 +39,27 @@ void mp_seq_multiply(const void *items, size_t item_sz, size_t len, size_t times for (size_t i = 0; i < times; i++) { size_t copy_sz = item_sz * len; memcpy(dest, items, copy_sz); - dest = (char*)dest + copy_sz; + dest = (char *)dest + copy_sz; } } #if MICROPY_PY_BUILTINS_SLICE bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice_t *indexes) { - mp_obj_t ostart, ostop, ostep; - mp_int_t start, stop; - mp_obj_slice_get(slice, &ostart, &ostop, &ostep); + mp_obj_slice_indices(slice, len, indexes); - if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { - indexes->step = mp_obj_get_int(ostep); - if (indexes->step == 0) { - mp_raise_ValueError("slice step cannot be zero"); - } - } else { - indexes->step = 1; - } - - if (ostart == mp_const_none) { - if (indexes->step > 0) { - start = 0; - } else { - start = len - 1; - } - } else { - start = mp_obj_get_int(ostart); - } - if (ostop == mp_const_none) { - if (indexes->step > 0) { - stop = len; - } else { - stop = 0; - } - } else { - stop = mp_obj_get_int(ostop); - if (stop >= 0 && indexes->step < 0) { - stop += 1; - } - } - - // Unlike subscription, out-of-bounds slice indexes are never error - if (start < 0) { - start = len + start; - if (start < 0) { - if (indexes->step < 0) { - start = -1; - } else { - start = 0; - } - } - } else if (indexes->step > 0 && (mp_uint_t)start > len) { - start = len; - } else if (indexes->step < 0 && (mp_uint_t)start >= len) { - start = len - 1; - } - if (stop < 0) { - stop = len + stop; - if (stop < 0) { - stop = -1; - } - if (indexes->step < 0) { - stop += 1; - } - } else if ((mp_uint_t)stop > len) { - stop = len; + // If the index is negative then stop points to the last item, not after it + if (indexes->step < 0) { + indexes->stop++; } // CPython returns empty sequence in such case, or point for assignment is at start - if (indexes->step > 0 && start > stop) { - stop = start; - } else if (indexes->step < 0 && start < stop) { - stop = start + 1; + if (indexes->step > 0 && indexes->start > indexes->stop) { + indexes->stop = indexes->start; + } else if (indexes->step < 0 && indexes->start < indexes->stop) { + indexes->stop = indexes->start + 1; } - indexes->start = start; - indexes->stop = stop; - return indexes->step == 1; } @@ -154,7 +96,7 @@ bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte * // Let's deal only with > & >= if (op == MP_BINARY_OP_LESS || op == MP_BINARY_OP_LESS_EQUAL) { - SWAP(const byte*, data1, data2); + SWAP(const byte *, data1, data2); SWAP(size_t, len1, len2); if (op == MP_BINARY_OP_LESS) { op = MP_BINARY_OP_MORE; @@ -221,7 +163,7 @@ bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp } // Otherwise, application of relation op gives the answer - return (mp_binary_op(op, items1[i], items2[i]) == mp_const_true); + return mp_binary_op(op, items1[i], items2[i]) == mp_const_true; } // If we had tie in the last element... @@ -241,7 +183,7 @@ bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp // Special-case of index() which searches for mp_obj_t mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args) { - mp_obj_type_t *type = mp_obj_get_type(args[0]); + const mp_obj_type_t *type = mp_obj_get_type(args[0]); mp_obj_t value = args[1]; size_t start = 0; size_t stop = len; @@ -266,9 +208,9 @@ mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, cons mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value) { size_t count = 0; for (size_t i = 0; i < len; i++) { - if (mp_obj_equal(items[i], value)) { - count++; - } + if (mp_obj_equal(items[i], value)) { + count++; + } } // Common sense says this cannot overflow small int