diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7250903 --- /dev/null +++ b/.gitignore @@ -0,0 +1,72 @@ +*~ +*.swo +*.swp +cscope.* +tags + +**/CMakeCache.txt +**/build_log.txt +**/cmake_install.cmake +**/flexspi_nor_debug/ +**/flexspi_nor_release/ +**/output.map +**/CMakeFiles +**/clean +**/armgcc/Makefile +**/flexspi_nor_sdram_debug/ +**/flexspi_nor_sdram_release/ +**/*.ninja_deps +**/*.ninja_log +**/build.ninja +**/rules.ninja + +*.s +*.i + +microej/MCXN947-*-CM4hardfp_GCC48-*/build/ +microej/MCXN947-*-CM4hardfp_GCC48-*/source/ + +BuildKit/bin/ +BuildKit/conf/ +BuildKit/lib/ +BuildKit/microej-build-repository/ +BuildKit/microej-module-repository/ +BuildKit/release.properties + +.java.app +.java.configuration +.java.fp +.java.mock +.*.java.app +.*.java.configuration +.*.java.fp +.*.java.mock +javasec.prop + +**/redlink.err +**/redlink.log +**/.gdb_history +gdb.cmd +**/application.out +**/bin +test_results/* +bsp/projects/nxpvee-ui/armgcc/debug/ +microej/vee-port-configuration/dropins/*.jar +microej/vee-port-configuration/dropins/include +microej/vee-port-configuration/dropins/javaAPIs +microej/vee-port-configuration/dropins/javaLibs +microej/vee-port-configuration/dropins/mocks +microej/vee-port-configuration/dropins/resources/ +microej/vee-port-configuration/dropins/scripts +microej/vee-port-configuration/dropins/tools/* +microej/vee-port-configuration/dropins/workbenchExtension_launchScriptFramework.jar +microej/vee-port-configuration/dropins/gpio/gpio_default.properties +bsp/projects/nxpvee-ui/armgcc/build_log.txt +bsp/projects/nxpvee-ui/armgcc/release/ +bsp/projects/microej/platform/ +scripts/pylib/build_helpers/__pycache__/ +scripts/west_commands/__pycache__/ +scripts/west_commands/runners/__pycache__/ +/build +bsp/projects/nxpvee-ui/armgcc/tree_version.c +bsp/mcux-sdk/ diff --git a/.vscode/cmake-kits.json b/.vscode/cmake-kits.json new file mode 100644 index 0000000..2648d06 --- /dev/null +++ b/.vscode/cmake-kits.json @@ -0,0 +1,14 @@ +[ + { + "name": "armgcc", + "keep": true, + "cmakeSettings": { + "LANGUAGE": "C", + "DEBUG_CONSOLE": "UART", + "POSTPROCESS_UTILITY": "${command:mcuxpresso.postProcessPath}", + "SdkRootDirPath": "${command:mcuxpresso.repoPath}" + }, + "keep": true, + "toolchainFile": "${workspaceFolder}/bsp/mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" + } +] diff --git a/.vscode/cmake-variants.json b/.vscode/cmake-variants.json new file mode 100644 index 0000000..c0f46f2 --- /dev/null +++ b/.vscode/cmake-variants.json @@ -0,0 +1,15 @@ +{ + "build_type": { + "default": "debug", + "choices": { + "debug": { + "short": "debug", + "buildType": "debug" + }, + "release": { + "short": "release", + "buildType": "release" + } + } + } +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..0cf15c5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "configurations": [ + { + "type": "cppdbg", + "name": "Debug project configuration", + "request": "launch", + "cwd": "${workspaceRoot}", + "MIMode": "gdb", + "setupCommands": [ + {"text": "set remotetimeout 600"}, + {"text": "set debug-file-directory"} + ], + "program": "", + "miDebuggerServerAddress": "", // Remote GDB server address. If this is provided, "debugServerPath" will not be auto-completed. + "variables": { + "mcuxStopAtSymbol": "main", // Initial breakpoint + "mcuxSerialNumber": "", // Probe serial number. If not specified, the one from the selected debug probe (in extension view) will be used. + "mcuxAttach": "false", // Start debug in attach mode + "mcuxRemoteProbeType": "", // Remote Probe Type ("LinkServer", "SEGGER", "PEmicro") used only when connecting to a remote server + }, + "logging": { + "engineLogging": false + } + } + ] +} diff --git a/.vscode/mcuxpresso-tools.json b/.vscode/mcuxpresso-tools.json new file mode 100644 index 0000000..b4a8f80 --- /dev/null +++ b/.vscode/mcuxpresso-tools.json @@ -0,0 +1,26 @@ +{ + "version": "1.4", + "toolchainPath": "${env:ARMGCC_DIR}", + "linkedProjects": [], + "trustZoneType": "none", + "multicoreType": "none", + "debug": { + "linkserver": { + "device": "MCXN947:FRDM-MCXN947", + "core": "cm33_core0" + }, + "pemicro": {}, + "segger": { + "device": "Cortex-M33" + } + }, + "projectType": "sdk-freestanding", + "sdk": { + "version": "2.14.0", + "path": "${workspaceFolder}/bsp/mcux-sdk/core/", + "boardId": "frdmmcxn947", + "deviceId": "MCXN947", + "coreId": "cm33_core0_MCXN947", + "manifestId": "SDK_2.x_FRDM-MCXN947_manifest_v3_13" + } +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..58ae06e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,18 @@ +{ + "cmake.configureOnOpen": false, + "C_Cpp.errorSquiggles": "disabled", + "cmake.preferredGenerators": [ + "Unix Makefiles", + "Ninja", + "MinGW Makefiles" + ], + "cmake.sourceDirectory": "${workspaceFolder}/", + "cmake.buildDirectory": "${workspaceFolder}/build/${buildType}", + + "cmake.configureArgs": [ + "-DENABLE_NET=1", + "-DENABLE_SEC=1", + "-DENABLE_AI=0", + "-DJMAIN=com.nxp.simpleGFX.SimpleGFX" + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..000e580 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,33 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "cmake", + "label": "CMake: build", + "command": "build", + "targets": [ + "all" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [], + "detail": "CMake template build task" + }, + { + "type": "cmake", + "label": "CMake: clean", + "command": "clean", + "problemMatcher": [], + "detail": "CMake template clean task" + }, + { + "type": "cmake", + "label": "CMake: configure", + "command": "configure", + "problemMatcher": [], + "detail": "CMake template configure task" + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..31bdf97 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog +All notable changes to this project will be documented in this file. + +## [1.0.0] - Date TBD + +### Added + +- Add MicroEJ CORE support. +- Add MicroEJ FS support. +- Add MicroEJ display support. +- Add MicroEJ NET support. +- Add MicroEJ ECOM-NETWORK support. +- Add NXP AI support. +- Initial release of the VEE Port. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..76ec741 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_minimum_required(VERSION 3.2) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE debug) +endif() + +if(NOT CMAKE_TOOLCHAIN_FILE) + set(CMAKE_TOOLCHAIN_FILE "bsp/mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake") +endif() + +project(947Vee) + + +SET(PROJDIRPATH ${CMAKE_CURRENT_SOURCE_DIR}) +SET(JC ${CMAKE_CURRENT_SOURCE_DIR}/microej/CMake/jcc.py) + +option(VALIDATION "with(out) VALIDATION option") +if(VALIDATION) + add_definitions(-DVALIDATION) +endif(VALIDATION) + + +set(ZEPHYR_BASE ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "") +set(CACHED_BOARD mcxn9xxbrk_cm33_cpu0 CACHE STRING "") +set(ZEPHYR_RUNNERS_YAML ${CMAKE_CURRENT_SOURCE_DIR}/build/runners.yaml CACHE STRING "") +set(CONFIG_FLASH_BASE_ADDRESS 0x10000000 CACHE STRING "") +set(CMAKE_GDB gdb-multiarch CACHE STRING "") +set(BOARD_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "") + + +add_custom_target(runners_yaml_props_target) +add_custom_target(config_props_target) + + +set(ignoreMe "${WEST_PYTHON}") + +include(cmake/modules/extensions.cmake OPTIONAL) +include(cmake/board/board.cmake OPTIONAL) + + +add_subdirectory(microej) +add_subdirectory(bsp/projects/nxpvee-ui/armgcc) +add_subdirectory(cmake/flash) + +add_dependencies(nxpvee_ui.elf APPS) + +function(config_append content) + # Append ${content}\n to a target property which is later evaluated as a + # generator expression when writing the flash runner yaml file. + # We define this function here to have access to the `flash` target. + + set_property( + TARGET config_props_target + APPEND_STRING + PROPERTY config_contents + "${content}\n" + ) +endfunction() + + +function(create_config) + set(config_file "${PROJECT_BINARY_DIR}/.config") + +config_append ("CONFIG_FLASH_BASE_ADDRESS=${CONFIG_FLASH_BASE_ADDRESS}") + + # Write the final contents and set its location in the cache. + file(GENERATE OUTPUT "${config_file}" CONTENT + $) +endfunction() + +create_config() diff --git a/Documentation/pictures/MCXN947/frdm-mcxn947.jpg b/Documentation/pictures/MCXN947/frdm-mcxn947.jpg new file mode 100644 index 0000000..f5417b2 Binary files /dev/null and b/Documentation/pictures/MCXN947/frdm-mcxn947.jpg differ diff --git a/Documentation/pictures/MCXN947/lcd-par-s035.jpg b/Documentation/pictures/MCXN947/lcd-par-s035.jpg new file mode 100644 index 0000000..f7004c5 Binary files /dev/null and b/Documentation/pictures/MCXN947/lcd-par-s035.jpg differ diff --git a/Documentation/pictures/MCXN947/sdk_build_mock.png b/Documentation/pictures/MCXN947/sdk_build_mock.png new file mode 100644 index 0000000..c4dad87 Binary files /dev/null and b/Documentation/pictures/MCXN947/sdk_build_mock.png differ diff --git a/Documentation/pictures/MCXN947/sdk_build_platform.png b/Documentation/pictures/MCXN947/sdk_build_platform.png new file mode 100644 index 0000000..b8f4595 Binary files /dev/null and b/Documentation/pictures/MCXN947/sdk_build_platform.png differ diff --git a/Documentation/pictures/MCXN947/sdk_choose_app_mode.png b/Documentation/pictures/MCXN947/sdk_choose_app_mode.png new file mode 100644 index 0000000..bdbdf05 Binary files /dev/null and b/Documentation/pictures/MCXN947/sdk_choose_app_mode.png differ diff --git a/Documentation/pictures/MCXN947/sdk_mockup_declaration_in_platform.png b/Documentation/pictures/MCXN947/sdk_mockup_declaration_in_platform.png new file mode 100644 index 0000000..311e2dc Binary files /dev/null and b/Documentation/pictures/MCXN947/sdk_mockup_declaration_in_platform.png differ diff --git a/Documentation/pictures/MCXN947/sdk_package_explorer.png b/Documentation/pictures/MCXN947/sdk_package_explorer.png new file mode 100644 index 0000000..de5abf8 Binary files /dev/null and b/Documentation/pictures/MCXN947/sdk_package_explorer.png differ diff --git a/Documentation/pictures/MCXN947/sdk_projects_list.png b/Documentation/pictures/MCXN947/sdk_projects_list.png new file mode 100644 index 0000000..cf11b52 Binary files /dev/null and b/Documentation/pictures/MCXN947/sdk_projects_list.png differ diff --git a/Documentation/pictures/MCXN947/sdk_run_as_microej_app.png b/Documentation/pictures/MCXN947/sdk_run_as_microej_app.png new file mode 100644 index 0000000..a677157 Binary files /dev/null and b/Documentation/pictures/MCXN947/sdk_run_as_microej_app.png differ diff --git a/Documentation/pictures/MCXN947/sdk_sim_simple.png b/Documentation/pictures/MCXN947/sdk_sim_simple.png new file mode 100644 index 0000000..82b10d7 Binary files /dev/null and b/Documentation/pictures/MCXN947/sdk_sim_simple.png differ diff --git a/Documentation/pictures/common/sdk6-button.png b/Documentation/pictures/common/sdk6-button.png new file mode 100644 index 0000000..c87cc20 Binary files /dev/null and b/Documentation/pictures/common/sdk6-button.png differ diff --git a/Documentation/pictures/common/sdk_existing_project.png b/Documentation/pictures/common/sdk_existing_project.png new file mode 100644 index 0000000..2cebc28 Binary files /dev/null and b/Documentation/pictures/common/sdk_existing_project.png differ diff --git a/Documentation/pictures/common/sdk_import.png b/Documentation/pictures/common/sdk_import.png new file mode 100644 index 0000000..802f019 Binary files /dev/null and b/Documentation/pictures/common/sdk_import.png differ diff --git a/Documentation/pictures/common/sdk_mockup_org_name_declaration.png b/Documentation/pictures/common/sdk_mockup_org_name_declaration.png new file mode 100644 index 0000000..f18d72f Binary files /dev/null and b/Documentation/pictures/common/sdk_mockup_org_name_declaration.png differ diff --git a/Documentation/pictures/common/vscode_load_project.jpg b/Documentation/pictures/common/vscode_load_project.jpg new file mode 100644 index 0000000..8e8ce58 Binary files /dev/null and b/Documentation/pictures/common/vscode_load_project.jpg differ diff --git a/Documentation/pictures/common/vscode_mcuxpr_build_debug.jpg b/Documentation/pictures/common/vscode_mcuxpr_build_debug.jpg new file mode 100644 index 0000000..3198595 Binary files /dev/null and b/Documentation/pictures/common/vscode_mcuxpr_build_debug.jpg differ diff --git a/Documentation/pictures/common/vscode_reset_probe_selection.jpg b/Documentation/pictures/common/vscode_reset_probe_selection.jpg new file mode 100644 index 0000000..361a7e9 Binary files /dev/null and b/Documentation/pictures/common/vscode_reset_probe_selection.jpg differ diff --git a/Documentation/pictures/common/vscode_scan_for_kits.jpg b/Documentation/pictures/common/vscode_scan_for_kits.jpg new file mode 100644 index 0000000..285281b Binary files /dev/null and b/Documentation/pictures/common/vscode_scan_for_kits.jpg differ diff --git a/Documentation/pictures/common/vscode_select_a_kit-1.jpg b/Documentation/pictures/common/vscode_select_a_kit-1.jpg new file mode 100644 index 0000000..63221c7 Binary files /dev/null and b/Documentation/pictures/common/vscode_select_a_kit-1.jpg differ diff --git a/Documentation/pictures/common/vscode_select_a_kit-2.jpg b/Documentation/pictures/common/vscode_select_a_kit-2.jpg new file mode 100644 index 0000000..8510ebd Binary files /dev/null and b/Documentation/pictures/common/vscode_select_a_kit-2.jpg differ diff --git a/Documentation/pictures/common/vscode_select_build.jpg b/Documentation/pictures/common/vscode_select_build.jpg new file mode 100644 index 0000000..da138a8 Binary files /dev/null and b/Documentation/pictures/common/vscode_select_build.jpg differ diff --git a/Documentation/pictures/common/vscode_select_configure.jpg b/Documentation/pictures/common/vscode_select_configure.jpg new file mode 100644 index 0000000..b0e4efe Binary files /dev/null and b/Documentation/pictures/common/vscode_select_configure.jpg differ diff --git a/Documentation/pictures/common/vscode_select_variant.jpg b/Documentation/pictures/common/vscode_select_variant.jpg new file mode 100644 index 0000000..4f048a9 Binary files /dev/null and b/Documentation/pictures/common/vscode_select_variant.jpg differ diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..a8537d3 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,752 @@ +LA_OPT_NXP_Software_License v54 February 2024 +IMPORTANT. Read the following NXP Software License Agreement ("Agreement") +completely. By selecting the "I Accept" button at the end of this page, or by +downloading, installing, or using the Licensed Software, you indicate that you +accept the terms of the Agreement, and you acknowledge that you have the +authority, for yourself or on behalf of your company, to bind your company to +these terms. You may then download or install the file. In the event of a +conflict between the terms of this Agreement and any license terms and +conditions for NXP’s proprietary software embedded anywhere in the Licensed +Software file, the terms of this Agreement shall control. If a separate +license agreement for the Licensed Software has been signed by you and NXP, +then that agreement shall govern your use of the Licensed Software and shall +supersede this Agreement. + +NXP SOFTWARE LICENSE AGREEMENT +This is a legal agreement between your employer, of which you are an authorized +representative, or, if you have no employer, you as an individual ("you" or +"Licensee"), and NXP B.V. ("NXP"). It concerns your rights to use the software +provided to you in binary or source code form and any accompanying written +materials (the "Licensed Software"). The Licensed Software may include any +updates or error corrections or documentation relating to the Licensed Software +provided to you by NXP under this Agreement. In consideration for NXP allowing +you to access the Licensed Software, you are agreeing to be bound by the terms +of this Agreement. If you do not agree to all of the terms of this Agreement, +do not download or install the Licensed Software. If you change your mind +later, stop using the Licensed Software and delete all copies of the Licensed +Software in your possession or control. Any copies of the Licensed Software +that you have already distributed, where permitted, and do not destroy will +continue to be governed by this Agreement. Your prior use will also continue to +be governed by this Agreement. +1. DEFINITIONS +1.1. "Affiliate" means, with respect to a party, any corporation or +other legal entity that now or hereafter Controls, is Controlled by or is under +common Control with such party; where "Control" means the direct or indirect +ownership of greater than fifty percent (50%) of the shares or similar +interests entitled to vote for the election of directors or other persons +performing similar functions. An entity is considered an Affiliate only so long +as such Control exists. +1.2 "Authorized System" means either (i) Licensee’s hardware product +which incorporates an NXP Product or (ii) Licensee’s software program which +is used exclusively in connection with an NXP Product and with which the +Licensed Software will be integrated. +1.3. "Derivative Work" means a work based upon one or more pre-existing +works. A work consisting of editorial revisions, annotations, elaborations, or +other modifications which, as a whole, represent an original work of +authorship, is a Derivative Work. +1.4 "Intellectual Property Rights" means any and all rights under statute, +common law or equity in and under copyrights, trade secrets, and patents +(including utility models), and analogous rights throughout the world, +including any applications for and the right to apply for, any of the foregoing. +1.5 "NXP Product" means a hardware product (e.g. a microprocessor, +microcontroller, sensor or digital signal processor) and/or services (e.g. +cloud platform services) supplied directly or indirectly from NXP or an NXP +Affiliate, unless there is a product specified in the Software Content +Register, in which case this definition is limited to such product. +1.6 "Software Content Register" means the documentation which may +accompany the Licensed Software which identifies the contents of the Licensed +Software, including but not limited to identification of any Third Party +Software, if any, and may also contain other related information as whether the +license in 2.3 is applicable. +1.7 "Third Party Software" means, any software included in the Licensed +Software that is not NXP proprietary software, and is not open source software, +and to which different license terms may apply. +2. LICENSE GRANT. +2.1. If you are not expressly granted the distribution license in +Section 2.3 in the Software Content Register, then you are only granted the +rights in Section 2.2 and not in 2.3. If you are expressly granted the +distribution license in Section 2.3 in the Software Content Register, then you +are granted the rights in both Section 2.2 and 2.3. +2.2. Standard License. Subject to the terms and conditions of this +Agreement, NXP grants you a worldwide, personal, non-transferable, +non-exclusive, non-sublicensable license, solely for the development of an +Authorized System: +(a) to use and reproduce the Licensed Software (and its Derivative Works +prepared under the license in Section 2.2(b)) solely in combination with a NXP +Product; and +(b) for Licensed Software provided to you in source code form (human +readable), to prepare Derivative Works of the Licensed Software solely for use +in combination with a NXP Product. +You may not distribute or sublicense the Licensed Software to others under the +license granted in this Section 2.2. +You may demonstrate the Licensed Software to your direct customers as part of +an Authorized System so long as such demonstration is directly controlled by +you and without prior approval by NXP; however, to all other third parties only +if NXP has provided its advance, written approval (e.g. email approval) of your +demonstrating the Licensed Software to specified third parties or at specified +event(s). You may not leave the Licensed Software with a direct customer or +any other third party at any time. +2.3. Additional Distribution License. If expressly authorized in the +Software Content Register, subject to the terms and conditions of this +Agreement, NXP grants you a worldwide, personal, non-transferable, +non-exclusive, non-sublicensable license solely in connection with your +manufacturing and distribution of an Authorized System: +(a) to manufacture (or have manufactured), distribute, and market the +Licensed Software (and its Derivative Works prepared under the license in +2.2(b)) in object code (machine readable format) only as part of, or embedded +within, Authorized Systems and not on a standalone basis solely for use in +combination with a NXP Product. Notwithstanding the foregoing, those files +marked as .h files ("Header files") may be distributed in source or object code +form, but only as part of, or embedded within Authorized Systems; and +(b) to copy and distribute as needed, solely in connection with an +Authorized System and for use in combination with a NXP Product, +non-confidential NXP information provided as part of the Licensed Software for +the purpose of maintaining and supporting Authorized Systems with which the +Licensed Software is integrated. +2.4 Separate license grants to Third Party Software, or other terms +applicable to the Licensed Software if different from those granted in this +Section 2, are contained in Appendix A. The Licensed Software may be +accompanied by a Software Content Register which will identify that portion of +the Licensed Software, if any, that is subject to the different terms in +Appendix A. +2.5. You may use subcontractors to exercise your rights under Section +2.2 and Section 2.3, if any, so long as you have an agreement in place with the +subcontractor containing confidentiality restrictions no less stringent than +those contained in this Agreement. You will remain liable for your +subcontractors’ adherence to the terms of this Agreement and for any and all +acts and omissions of such subcontractors with respect to this Agreement and +the Licensed Software. +3. LICENSE LIMITATIONS AND RESTRICTIONS. +3.1. The licenses granted above in Section 2 only extend to NXP +Intellectual Property Rights that would be infringed by the unmodified Licensed +Software prior to your preparation of any Derivative Work. +3.2. The Licensed Software is licensed to you, not sold. Title to +Licensed Software delivered hereunder remains vested in NXP or NXP’s licensor +and cannot be assigned or transferred. You are expressly forbidden from selling +or otherwise distributing the Licensed Software, or any portion thereof, except +as expressly permitted herein. This Agreement does not grant to you any implied +rights under any NXP or third party Intellectual Property Rights. +3.3. You may not translate, reverse engineer, decompile, or disassemble +the Licensed Software except to the extent applicable law specifically +prohibits such restriction. You must prohibit your subcontractors or customers +(if distribution is permitted) from translating, reverse engineering, +decompiling, or disassembling the Licensed Software except to the extent +applicable law specifically prohibits such restriction. +3.4. You must reproduce any and all of NXP’s (or its third-party +licensor’s) copyright notices and other proprietary legends on copies of +Licensed Software. +3.5. If you distribute the Licensed Software to the United States +Government, then the Licensed Software is "restricted computer software" and is +subject to FAR 52.227-19. +3.6. You grant to NXP a non-exclusive, non-transferable, irrevocable, +perpetual, worldwide, royalty-free, sub-licensable license under your +Intellectual Property Rights to use without restriction and for any purpose any +suggestion, comment or other feedback related to the Licensed Software +(including, but not limited to, error corrections and bug fixes). +3.7. You will not take or fail to take any action that could subject +the Licensed Software to an Excluded License. An Excluded License means any +license that requires, as a condition of use, modification or distribution of +software subject to the Excluded License, that such software or other software +combined and/or distributed with the software be (i) disclosed or distributed +in source code form; (ii) licensed for the purpose of making Derivative Works; +or (iii) redistributable at no charge. +3.8. You may not publish or distribute reports associated with the use +of the Licensed Software to anyone other than NXP. You may advise NXP of any +results obtained from your use of the Licensed Software, including any problems +or suggested improvements thereof, and NXP retains the right to use such +results and related information in any manner it deems appropriate. +4. OPEN SOURCE. Open source software included in the Licensed +Software is not licensed under the terms of this Agreement but is instead +licensed under the terms of the applicable open source license(s), such as the +BSD License, Apache License or the GNU Lesser General Public License. Your use +of the open source software is subject to the terms of each applicable license. +You must agree to the terms of each applicable license, or you cannot use the +open source software. +5. INTELLECTUAL PROPERTY RIGHTS. +Upon request, you must provide NXP the source code of any derivative of the +Licensed Software. +Unless prohibited by law, the following paragraph shall apply. Your +modifications to the Licensed Software, and all intellectual property rights +associated with, and title thereto, will be the property of NXP. You agree to +assign all, and hereby do assign all rights, title, and interest to any such +modifications to the Licensed Software to NXP and agree to provide all +assistance reasonably requested by NXP to establish, preserve or enforce such +right. Further, you agree to waive all moral rights relating to your +modifications to the Licensed Software, including, without limitation, all +rights of identification of authorship and all rights of approval, restriction, +or limitation on use or subsequent modification. Notwithstanding the +foregoing, you will have the license rights granted in Section 2 hereto to any +such modifications made by you or your licensees. +Otherwise, you agree to grant an irrevocable, worldwide, and perpetual license +to NXP to make, have made, use, sell, offer to sell, import, commercialize, +sublicense and reproduce your modifications or derivative works to the Licensed +Software without any payment to Licensee. You agree to provide all assistance +reasonably requested by NXP to establish, preserve or enforce such right. +6. ESSENTIAL PATENTS. NXP has no obligation to identify or obtain any +license to any Intellectual Property Right of a third-party that may be +necessary for use in connection with technology that is incorporated into the +Authorized System (whether or not as part of the Licensed Software). +7. TERM AND TERMINATION. This Agreement will remain in effect unless +terminated as provided in this Section. +7.1. You may terminate this Agreement immediately upon written notice +to NXP at the address provided below. +7.2. Either party may terminate this Agreement if the other party is in +default of any of the terms and conditions of this Agreement, and termination +is effective if the defaulting party fails to correct such default within 30 +days after written notice thereof by the non-defaulting party to the defaulting +party at the address below. +7.3. Notwithstanding the foregoing, NXP may terminate this Agreement +immediately upon written notice if you: breach any of your confidentiality +obligations or the license restrictions under this Agreement; become bankrupt, +insolvent, or file a petition for bankruptcy or insolvency; make an assignment +for the benefit of its creditors; enter proceedings for winding up or +dissolution; are dissolved; or are nationalized or become subject to the +expropriation of all or substantially all of your business or assets. +7.4. Upon termination of this Agreement, all licenses granted under +Section 2 will expire. +7.5. After termination of this Agreement by either party you will +destroy all parts of Licensed Software and its Derivative Works (if any) and +will provide to NXP a statement certifying the same. +7.6. Notwithstanding the termination of this Agreement for any reason, +the terms of Sections 1 and 3 through 24 will survive. +8. SUPPORT. NXP is not obligated to provide any support, upgrades or +new releases of the Licensed Software under this Agreement. If you wish, you +may contact NXP and report problems and provide suggestions regarding the +Licensed Software. NXP has no obligation to respond to such a problem report or +suggestion. NXP may make changes to the Licensed Software at any time, without +any obligation to notify or provide updated versions of the Licensed Software +to you. +9. NO WARRANTY. To the maximum extent permitted by law, NXP expressly +disclaims any warranty for the Licensed Software. The Licensed Software is +provided "AS IS", without warranty of any kind, either express or implied, +including without limitation the implied warranties of merchantability, fitness +for a particular purpose, or non-infringement. You assume the entire risk +arising out of the use or performance of the licensed software, or any systems +you design using the licensed software (if any). +10. INDEMNITY. You agree to fully defend and indemnify NXP from all +claims, liabilities, and costs (including reasonable attorney’s fees) related +to (1) your use (including your subcontractor’s or distributee’s use, if +permitted) of the Licensed Software or (2) your violation of the terms and +conditions of this Agreement. +11. LIMITATION OF LIABILITY. EXCLUDING LIABILITY FOR A BREACH OF +SECTION 2 (LICENSE GRANTS), SECTION 3 (LICENSE LIMITATIONS AND RESTRICTIONS), +SECTION 16 (CONFIDENTIAL INFORMATION), OR CLAIMS UNDER SECTION 10 (INDEMNITY), +IN NO EVENT WILL EITHER PARTY BE LIABLE, WHETHER IN CONTRACT, TORT, OR +OTHERWISE, FOR ANY INCIDENTAL, SPECIAL, INDIRECT, CONSEQUENTIAL OR PUNITIVE +DAMAGES, INCLUDING, BUT NOT LIMITED TO, DAMAGES FOR ANY LOSS OF USE, LOSS OF +TIME, INCONVENIENCE, COMMERCIAL LOSS, OR LOST PROFITS, SAVINGS, OR REVENUES, TO +THE FULL EXTENT SUCH MAY BE DISCLAIMED BY LAW. NXP’S TOTAL LIABILITY FOR ALL +COSTS, DAMAGES, CLAIMS, OR LOSSES WHATSOEVER ARISING OUT OF OR IN CONNECTION +WITH THIS AGREEMENT OR PRODUCT(S) SUPPLIED UNDER THIS AGREEMENT IS LIMITED TO +THE AGGREGATE AMOUNT PAID BY YOU TO NXP IN CONNECTION WITH THE LICENSED +SOFTWARE PROVIDED UNDER THIS AGREEMENT TO WHICH LOSSES OR DAMAGES ARE CLAIMED. +12. EXPORT COMPLIANCE. Each party shall comply with all applicable +export and import control laws and regulations including but not limited to the +US Export Administration Regulation (including restrictions on certain military +end uses and military end users as specified in Section 15 C.F.R. § 744.21 and +prohibited party lists issued by other federal governments), Catch-all +regulations and all national and international embargoes. Each party further +agrees that it will not knowingly transfer, divert, export or re-export, +directly or indirectly, any product, software, including software source code, +or technology restricted by such regulations or by other applicable national +regulations, received from the other party under this Agreement, or any direct +product of such software or technical data to any person, firm, entity, country +or destination to which such transfer, diversion, export or re-export is +restricted or prohibited, without obtaining prior written authorization from +the applicable competent government authorities to the extent required by those +laws. +13. GOVERNMENT CONTRACT COMPLIANCE +13.1. If you sell Authorized Systems directly to any government or public +entity, including U.S., state, local, foreign or international governments or +public entities, or indirectly via a prime contractor or subcontractor of such +governments or entities, NXP makes no representations, certifications, or +warranties whatsoever about compliance with government or public entity +acquisition statutes or regulations, including, without limitation, statutes or +regulations that may relate to pricing, quality, origin or content. +13.2. The Licensed Software has been developed at private expense and is a +"Commercial Item" as defined in 48 C.F.R. Section 2.101, consisting of +"Commercial Computer Software", and/or "Commercial Computer Software +Documentation," as such terms are used in 48 C.F.R. Section 12.212 (or 48 +C.F.R. Section 227.7202, as applicable) and may only be licensed to or shared +with U.S. Government end users in object code form as part of, or embedded +within, Authorized Systems. Any agreement pursuant to which you share the +Licensed Software will include a provision that reiterates the limitations of +this document and requires all sub-agreements to similarly contain such +limitations. +14. CRITICAL APPLICATIONS. In some cases, NXP may promote certain +software for use in the development of, or for incorporation into, products or +services (a) used in applications requiring fail-safe performance or (b) in +which failure could lead to death, personal injury, or severe physical or +environmental damage (these products and services are referred to as "Critical +Applications"). NXP’s goal is to educate customers so that they can design +their own end-product solutions to meet applicable functional safety standards +and requirements. Licensee makes the ultimate design decisions regarding its +products and is solely responsible for compliance with all legal, regulatory, +safety, and security related requirements concerning its products, regardless +of any information or support that may be provided by NXP. As such, Licensee +assumes all risk related to use of the Licensed Software in Critical +Applications and NXP SHALL NOT BE LIABLE FOR ANY SUCH USE IN CRITICAL +APPLICATIONS BY LICENSEE. Accordingly, Licensee will indemnify and hold NXP +harmless from any claims, liabilities, damages and associated costs and +expenses (including attorneys’ fees) that NXP may incur related to +Licensee’s incorporation of the Licensed Software in a Critical Application. +15. CHOICE OF LAW; VENUE. This Agreement will be governed by, +construed, and enforced in accordance with the laws of The Netherlands, without +regard to conflicts of laws principles, will apply to all matters relating to +this Agreement or the Licensed Software, and you agree that any litigation will +be subject to the exclusive jurisdiction of the courts of Amsterdam, The +Netherlands. The United Nations Convention on Contracts for the International +Sale of Goods will not apply to this document. +16. CONFIDENTIAL INFORMATION. Subject to the license grants and +restrictions contained herein, you must treat the Licensed Software as +confidential information and you agree to retain the Licensed Software in +confidence perpetually. You may not disclose any part of the Licensed Software +to anyone other than distributees in accordance with Section 2.3 and employees, +or subcontractors in accordance with Section 2.5, who have a need to know of +the Licensed Software and who have executed written agreements obligating them +to protect such Licensed Software to at least the same degree of +confidentiality as in this Agreement. You agree to use the same degree of care, +but no less than a reasonable degree of care, with the Licensed Software as you +do with your own confidential information. You may disclose Licensed Software +to the extent required by a court or under operation of law or order provided +that you notify NXP of such requirement prior to disclosure, which you only +disclose the minimum of the required information, and that you allow NXP the +opportunity to object to such court or other legal body requiring such +disclosure. +17. TRADEMARKS. You are not authorized to use any NXP trademarks, brand +names, or logos. +18. ENTIRE AGREEMENT. This Agreement constitutes the entire agreement +between you and NXP regarding the subject matter of this Agreement, and +supersedes all prior communications, negotiations, understandings, agreements +or representations, either written or oral, if any. This Agreement may only be +amended in written form, signed by you and NXP. +19. SEVERABILITY. If any provision of this Agreement is held for any +reason to be invalid or unenforceable, then the remaining provisions of this +Agreement will be unimpaired and, unless a modification or replacement of the +invalid or unenforceable provision is further held to deprive you or NXP of a +material benefit, in which case the Agreement will immediately terminate, the +invalid or unenforceable provision will be replaced with a provision that is +valid and enforceable and that comes closest to the intention underlying the +invalid or unenforceable provision. +20. NO WAIVER. The waiver by NXP of any breach of any provision of this +Agreement will not operate or be construed as a waiver of any other or a +subsequent breach of the same or a different provision. +21. AUDIT. You will keep full, clear and accurate records with respect +to your compliance with the limited license rights granted under this Agreement +for three years following expiration or termination of this Agreement. NXP will +have the right, either itself or through an independent certified public +accountant to examine and audit, at NXP’s expense, not more than once a year, +and during normal business hours, all such records that may bear upon your +compliance with the limited license rights granted above. You must make prompt +adjustment to compensate for any errors and/or omissions disclosed by such +examination or audit. +22. NOTICES. All notices and communications under this +Agreement will be made in writing, and will be effective when received at the +following addresses: +NXP: +NXP B.V. +High Tech Campus 60 +5656 AG Eindhoven +The Netherlands +ATTN: Legal Department + +You: +The address provided at registration will be used. + +23. RELATIONSHIP OF THE PARTIES. The parties are independent +contractors. Nothing in this Agreement will be construed to create any +partnership, joint venture, or similar relationship. Neither party is +authorized to bind the other to any obligations with third parties. +24. SUCCESSION AND ASSIGNMENT. This Agreement will be binding upon and +inure to the benefit of the parties and their permitted successors and assigns. + You may not assign this Agreement, or any part of this Agreement, without the +prior written approval of NXP, which approval will not be unreasonably withheld +or delayed. NXP may assign this Agreement, or any part of this Agreement, in +its sole discretion. +25. PRIVACY. By agreeing to this Agreement and/or utilizing the Licensed +Software, Licensee consents to use of certain personal information, including +but not limited to name, email address, and location, for the purpose of +NXP’s internal analysis regarding future software offerings. NXP’s +complete Privacy Statement can be found at: +https://www.nxp.com/company/our-company/about-nxp/privacy-statement:PRIVACYPRACT +ICES. + +APPENDIX A +Other License Grants and Restrictions: + +The Licensed Software may include some or all of the following software, which +is either 1) Third Party Software or 2) NXP proprietary software subject to +different terms than those in the Agreement. If the Software Content Register +that accompanies the Licensed Software identifies any of the following Third +Party Software or specific components of the NXP proprietary software, the +following terms apply to the extent they deviate from the terms in the +Agreement: + +AGGIOS, Inc.: EnergyLab LITE and Seed software are distributed by NXP under +license from AGGIOS, Inc. Your use of AGGIOS software, as the Licensee, is +subject to the following: (i) use of AGGIOS software is limited to object code +and Authorized System only; (ii) Licensee may not sublicense the AGGIOS +software to any third party; (iii) Licensee is only granted an evaluation +license for the Seed software, defined as license to use the Seed software +internally for own evaluation purposes, limited to three (3) months. Further +rights including but not limited to production deployment must be obtained +directly from AGGIOS, Inc. + +Airbiquity Inc.: The Airbiquity software may only be used in object code and +Licensee may not sublicense the Airbiquity software to any third party. +Licensee’s license to use the Airbiquity software expires on June 30, 2024. + +Amazon: Use of the Amazon software constitutes your acceptance of the terms of +the Amazon Program Materials License Agreement (including the AVS Component +Schedule, if applicable), located at +https://developer.amazon.com/support/legal/pml. All Amazon software is hereby +designated "Amazon confidential". With the exception of the binary library of +the Amazon Wake Word Engine for "Alexa", all Amazon software is also hereby +designated as "Restricted Program Materials". Amazon is a third-party +beneficiary to this Agreement with respect to the Amazon software. + +Amazon Web Services, Inc.: AWS is an intended third-party beneficiary to this +Agreement with respect to the Greengrass software. If you have an account with +AWS that is not in good standing, you may not download, install, use or +distribute the Greengrass software. You will comply with all instructions and +requirements in any integration documents, guidelines, or other documentation +AWS provides. The license to the Greengrass software will immediately terminate +without notice if you (a) fail to comply with this Agreement or any other +agreement with AWS, (b) fail to make timely payment for any AWS service, (c) +fail to implement AWS updates, or (d) bring any action for intellectual +property infringement against AWS or any AWS customer utilizing AWS services. +Any dispute or claim relating to your use of the Greengrass software will be +resolved by binding arbitration, rather than in court, except that you may +assert claims in small claims court if your claims qualify. + +Amazon: AWS Fleetwise software must be used consistent with the terms found +here: https://github.com/aws/aws-iot-fleetwise-edge/blob/main/LICENSE. + +Amphion Semiconductor Ltd.: Distribution of Amphion software must be a part of, +or embedded within, Authorized Systems that include an Amphion Video Decoder. + +Apple MFi Software Development Kit: Use of Apple MFi Software and associated +documentation is restricted to current Apple MFi licensees in accordance with +the terms of their own valid and in-effect license from Apple. + +Aquantia Corp.: You may use Aquantia's API binaries solely to flash the API +software to an NXP Product which mates with an Aquantia device. + +Argus Cyber Security: The Argus software may only be used in object code and +only for evaluation and demonstration purposes. + +Arm Toolkit: This tool is owned by Arm Limited. You may not reverse engineer, +decompile or dissemble any ARM Toolkit. You agree to abide by any third-party +IP requirements, including the relevant license terms where applicable, where +such third-party IP is identified in the documentation provided with the ARM +Toolkit. You may not copy the Arm Toolkit except solely for archival and backup +purposes provided all notices are preserved. Arm disclaims any and all +liability related to your use of the ARM Toolkit. + +Atheros: Use of Atheros software is limited to evaluation and demonstration +only. Permitted distributions must be similarly limited. Further rights must +be obtained directly from Atheros. + +ATI (AMD): Distribution of ATI software must be a part of, or embedded within, +Authorized Systems that include a ATI graphics processor core. + +Au-Zone Technologies: eIQ Portal, Model Tool, DeepViewRT and ModelRunner are +distributed by NXP under license from Au-Zone Technologies. Your use of the +Licensed Software, examples and related documentation is subject to the +following: +(1) Use of Software is limited to Authorized System only +(2) In no event may Licensee Sublicense the Software +(3) AU-ZONE TECHNOLOGIES SHALL NOT BE LIABLE FOR USE OF LICENSED +SOFTWARE IN CRITICAL APPLICATIONS BY LICENSEE + +Broadcom Corporation: Your use of Broadcom Corporation software is restricted +to Authorized Systems that incorporate a compatible integrated circuit device +manufactured or sold by Broadcom. + +Cadence Design Systems: Use of Cadence audio codec software is limited to +distribution only of one copy per single NXP Product. The license granted +herein to the Cadence Design Systems HiFi aacPlus Audio Decoder software does +not include a license to the AAC family of technologies which you or your +customer may need to obtain. Configuration tool outputs may only be distributed +by licensees of the relevant Cadence SDK and distribution is limited to +distribution of one copy embedded in a single NXP Product. Your use of Cadence +NatureDSP Libraries whether in source code or in binary is restricted to NXP +SoC based systems or emulation enablement based on NXP SoC. + +CEVA D.S.P. Ltd. And CEVA Technologies Inc. ("CEVA"): The CEVA-SPF2 linear +algebra, CEVA-SPF2 Neural Network Libraries, CEVA-SPF2 Core Libraries, +CEVA-SPF2 OpenAMP and CEVA-SPF2 STL licensed modules are owned by CEVA and such +materials may only be used in connection with an NXP product containing the +S250 or S125 integrated circuits, whether or not the CEVA-SPF2 Core is +physically implemented and/or enabled on such NXP product + +Cirque Corporation: Use of Cirque Corporation technology is limited to +evaluation, demonstration, or certification testing only. Permitted +distributions must be similarly limited. Further rights, including but not +limited to ANY commercial distribution rights, must be obtained directly from +Cirque Corporation. + +Coding Technologies (Dolby Labs): Use of CTS software is limited to evaluation +and demonstration only. Permitted distributions must be similarly limited. +Further rights must be obtained from Dolby Laboratories. + +Coremark: Use of the Coremark benchmarking software is subject to the +following terms and conditions: +https://github.com/eembc/coremark/blob/main/LICENSE.md + +CSR: Use of Cambridge Silicon Radio, Inc. ("CSR") software is limited to +evaluation and demonstration only. Permitted distributions must be similarly +limited. Further rights must be obtained directly from CSR. + +Crank: Use of Crank Software Inc. software is limited to evaluation and +demonstration only. Permitted distributions must be similarly limited. Further +rights must be obtained directly from Crank Software Inc. + +Cypress Semiconductor Corporation: WWD RTOS source code may only be used in +accordance with the Cypress IOT Community License Agreement obtained directly +from Cypress Semiconductor Corporation. + +Elektrobit Automotive GmbH ("EB"): EB software must be used consistent with the +EB License Terms and Conditions, Version 1.4 (Dec 2019) found here: +https://www.elektrobit.com/legal-notice/ . Licensee is only granted an +evaluation license for the EB software, defined as license to use the EB +software internally for own evaluation purposes, limited to three (3) months. +Production deployment of the EB software using this license is prohibited. See +additionally Section 2.1.1 EB EULA. + +Embedded Systems Academy GmbH (EmSA): Any use of Micro CANopen Plus is subject +to the acceptance of the license conditions described in the LICENSE.INFO file +distributed with all example projects and in the documentation and the +additional clause described below. +Clause 1: Micro CANopen Plus may not be used for any competitive or comparative +purpose, including the publication of any form of run time or compile time +metric, without the express permission of EmSA. + +Fenopix Technologies Private Limited: Under no circumstances may the CanvasJS +software product be used in any way that would compete with any product from +Fenopix. License to the CanvasJS software will terminate immediately without +notice if Licensee fail to comply with any provision of this Agreement. + +Fraunhofer IIS: Fraunhofer MPEG Audio Decoder (Fraunhofer copyright) - If you +are provided MPEG-H decoding functionality, you understand that NXP will +provide Fraunhofer your name and contact information. + +Future Technology Devices International Ltd.: Future Technology Devices +International software must be used consistent with the terms found here: +http://www.ftdichip.com/Drivers/FTDriverLicenceTerms.htm + +Global Locate (Broadcom Corporation): Use of Global Locate, Inc. software is +limited to evaluation and demonstration only. Permitted distributions must be +similarly limited. Further rights must be obtained from Global Locate. + +IAR Systems: Use of IAR flashloader or any IAR source code is subject to the +terms of the IAR Source License located within the IAR zip package. The IAR +Source License applies to linker command files, example projects unless another +license is explicitly stated, the cstartup code, low_level_init.c, and some +other low-level runtime library files. + +LC3plus: the LC3plus Low Complexity Communication Codec Plus (LC3plus) per ETSI +TS 103 634 V1.3.1, is subject to ETSI Intellectual Property Rights Policy, See +https://portal.etsi.org/directives/45_directives_jun_2022.pdf. For application +in an End Product, Fraunhofer communication applies, see +https://www.iis.fraunhofer.de/en/ff/amm/communication/lc3.html + +Lumissil: Use of the Lumissil software constitutes your acceptance of the terms +of the Lumissil Software License Agreement. A link to the agreement is +incorporated as follows: +https://www.lumissil.com/assets/pdf/support/2023%20Lumissil%20IS3xCG5317%20Softw +are%20License%20Agreement%20NXP.pdf . + +Microsoft: Except for Microsoft PlayReady software, if the Licensed Software +includes software owned by Microsoft Corporation ("Microsoft"), it is subject +to the terms of your license with Microsoft (the "Microsoft Underlying Licensed +Software") and as such, NXP grants no license to you, beyond evaluation and +demonstration in connection with NXP processors, in the Microsoft Underlying +Licensed Software. You must separately obtain rights beyond evaluation and +demonstration in connection with the Microsoft Underlying Licensed Software +from Microsoft. Microsoft does not provide support services for the components +provided to you through this Agreement. If you have any questions or require +technical assistance, please contact NXP. Microsoft Corporation is a third +party beneficiary to this Agreement with the right to enforce the terms of this +Agreement. TO THE MAXIMUM EXTENT PERMITTED BY LAW, MICROSOFT AND ITS +AFFILIATES DISCLAIM ANY WARRANTIES FOR THE MICROSOFT UNDERLYING LICENSED +SOFTWARE. TO THE MAXIMUM EXTENT PERMITTED BY LAW, NEITHER MICROSOFT NOR ITS +AFFILIATES WILL BE LIABLE, WHETHER IN CONTRACT, TORT, OR OTHERWISE, FOR ANY +DIRECT, INCIDENTAL, SPECIAL, INDIRECT, CONSEQUENTIAL OR PUNITIVE DAMAGES, +INCLUDING, BUT NOT LIMITED TO, DAMAGES FOR ANY LOSS OF USE, LOSS OF TIME, +INCONVENIENCE, COMMERCIAL LOSS, OR LOST PROFITS, SAVINGS, OR REVENUES, ARISING +FROM THE FROM THE USE OF THE MICROSOFT UNDERLYING LICENSED SOFTWARE. With +respect to the Microsoft PlayReady software, you will have the license rights +granted in Section 2, provided that you may not use the Microsoft PlayReady +software unless you have entered into a Microsoft PlayReady Master Agreement +and license directly with Microsoft. + +MindTree: Notwithstanding the terms contained in Section 2.3 (a), if the +Licensed Software includes proprietary software of MindTree in source code +format, Licensee may make modifications and create derivative works only to the +extent necessary for debugging of the Licensed Software. + +MM SOLUTIONS AD: Use of MM SOLUTIONS AEC (Auto Exposure Control) and AWB (Auto +White Balance) software is limited to demonstration, testing, and evaluation +only. In no event may Licensee distribute or sublicense the MM SOLUTIONS +software. Further rights must be obtained directly from MM SOLUTIONS. + +MPEG LA: Use of MPEG LA audio or video codec technology is limited to +evaluation and demonstration only. Permitted distributions must be similarly +limited. Further rights must be obtained directly from MPEG LA. + +MQX RTOS Code: MQX RTOS source code may not be re-distributed by any NXP +Licensee under any circumstance, even by a signed written amendment to this +Agreement. + +NXP Voice Software: VoiceSpot, VoiceSeeker (including AEC), VIT Speech to +Intent, and Conversa may be used for evaluation or demonstration purposes only. +Any commercial distribution rights are subject to a separate royalty agreement +obtained from NXP. + +NXP Wireless Charging Library: License to the Software is limited to use in +inductive coupling or wireless charging applications + +ON Semiconductor: ON Semiconductor AP1302 Image Signal Processor Initialization +Binaries must be used consistent with the terms found here: +https://github.com/ONSemiconductor/ap1302_binaries/blob/main/AP1302%20Software%2 +0License%20Agreement.pdf + +Opus: Use of Opus software must be consistent with the terms of the Opus +license which can be found at: http://www.opus-codec.org/license/ + +Oracle JRE (Java): The Oracle JRE must be used consistent with terms found +here: http://java.com/license + +P&E Micro: P&E Software must be used consistent with the terms found here: +http://www.pemicro.com/licenses/gdbserver/license_gdb.pdf + +Pro Design Electronic: Licensee may not modify, create derivative works based +on, or copy the Pro Design software, documentation, hardware execution key or +the accompanying materials. Licensee shall not use Pro Design's or any of its +licensors names, logos or trademarks to market the Authorized System. Only NXP +customers and distributors are permitted to further redistribute the Pro Design +software and only as part of an Authorized System which contains the Pro Design +software. + +Qualcomm Atheros, Inc.: Notwithstanding anything in this Agreement, Qualcomm +Atheros, Inc. Wi-Fi software must be used strictly in accordance with the +Qualcomm Atheros, Inc. Technology License Agreement that accompanies such +software. Any other use is expressly prohibited. + +Real Networks - GStreamer Optimized Real Format Client Code implementation or +OpenMax Optimized Real Format Client Code: Use of the GStreamer Optimized Real +Format Client Code, or OpenMax Optimized Real Format Client code is restricted +to applications in the automotive market. Licensee must be a final +manufacturer in good standing with a current license with Real Networks for the +commercial use and distribution of products containing the GStreamer Optimized +Real Format Client Code implementation or OpenMax Optimized Real Format Client +Code + +Real-Time Innovations, Inc.: Not withstanding anything in this Agreement, +Real-Time Innovations, Inc. software must be used strictly in accordance with +Real-Time Innovations, Inc.'s Automotive Software Evaluation License Agreement, +available here: +https://www.rti.com/hubfs/_Collateral/Services_and_Support/Automotive_Evaluation +_SLA_90_dayNXP.pdf . Any other use is expressly prohibited. + +RivieraWaves SAS (a member of the CEVA, Inc. family of companies): You may not +use the RivieraWaves intellectual property licensed under this Agreement if you +develop, market, and/or license products similar to such RivieraWaves +intellectual property. Such use constitutes a breach of this Agreement. Any +such use rights must be obtained directly from RivieraWaves. + +SanDisk Corporation: If the Licensed Software includes software developed by +SanDisk Corporation ("SanDisk"), you must separately obtain the rights to +reproduce and distribute this software in source code form from SanDisk. +Please follow these easy steps to obtain the license and software: +(1) Contact your local SanDisk sales representative to obtain the SanDisk +License Agreement. +(2) Sign the license agreement. Fax the signed agreement to SanDisk USA +marketing department at 408-542-0403. The license will be valid when fully +executed by SanDisk. +(3) If you have specific questions, please send an email to sales@sandisk.com +You may only use the SanDisk Corporation Licensed Software on products +compatible with a SanDisk Secure Digital Card. You may not use the SanDisk +Corporation Licensed Software on any memory device product. SanDisk retains +all rights to any modifications or derivative works to the SanDisk Corporation +Licensed Software that you may create. + +SEGGER Microcontroller - emWin Software: Your use of SEGGER emWin software and +components is restricted for development of NXP ARM7, ARM9, Cortex-M0, +Cortex-M3, Cortex-M4, Cortex-M33, Cortex-M7, and Cortex-A7 based products only. + +SEGGER Microcontroller - J-Link/J-Trace Software: Segger software must be used +consistent with the terms found here: http://www.segger.com/jlink-software.html + +SEVENSTAX - Not withstanding anything in this Agreement, SEVENSTAX GmbH +software must be used for evaluation purposes only, in strict accordance with +the SEVENSTAX License Agreement, available here: +https://www.sevenstax.de/fileadmin/documents/SEVENSTAX-NX-ESLA.txt. Any other +use, and embedding the software into commercial products, is expressly +prohibited. +Synopsys/BLE Software: Your use of the Synopsys/BLE Software and related +documentation is subject to the following: +(1) Synopsys is third-party beneficiaries of, and thus may enforce against you, +the license restrictions and confidentiality obligations in this agreement with +respect to their intellectual property and proprietary information. +(2) Your distribution of the Licensed Software shall subject any recipient to a +written agreement at least as protective of the Licensed Software as provided +in this Agreement. + +Synopsys/Target Compiler Technologies: Your use of the Synopsys/Target Compiler +Technologies Licensed Software and related documentation is subject to the +following: +(1) Duration of the license for the Licensed Software is limited to 12 months, +unless otherwise specified in the license file. +(2) The Licensed Software is usable by one user at a time on a single +designated computer, unless otherwise agreed by Synopsys. +(3) Licensed Software and documentation are to be used only on a designated +computer at the designated physical address provided by you on the APEX license +form. +(4) The Licensed Software is not sub-licensable. + +T2 Labs / T2 Software: As a condition to the grant of any license under this +Agreement, you represent and warrant that you will comply with all licenses, +agreements, rules and bylaws of the Bluetooth SIG (Special Interest Group ) +applicable to the licensed software and documentation and its use which may +affect when and if you may take certain actions under licenses granted +hereunder. + +The license grant under this Agreement is conditional to you being (i) a +Bluetooth SIG Associate member until such time as the specifications for the +software are made public to Bluetooth SIG members of any level and (ii) +thereafter a Bluetooth SIG member of any level. + +Notwithstanding the terms contained in Section 2.3 (a), if the licensed +software includes proprietary software in source code format, you may make +modifications and create derivative works only to the extent necessary for +improving the performance of the source code with the NXP products or your +products and for creating enhancements of such products. You may not further +sublicense or otherwise distribute the source code, or any modifications or +derivatives thereof as stand-alone products. You will be responsible for +qualifying any modifications or derivatives with the Bluetooth SIG and any +other qualifying bodies. + +TARA Systems: Use of TARA Systems GUI technology Embedded Wizard is limited to +evaluation and demonstration only. Permitted distributions must be similarly +limited. Further rights must be obtained directly from TARA Systems. + +Teensyduino Core Library: If the Teensyduino Core Library or documentation is +incorporated into a build system that allows selection among a list of target +devices, then similar target devices manufactured by PJRC.com must be included +in the list of target devices and selectable in the same manner. + +Texas Instruments: Your use of Texas Instruments Inc. WiLink8 Licensed Software +is restricted to NXP SoC based systems that include a compatible connectivity +device manufactured by TI. + +TES Electronic Solutions Germany (TES): TES 3D Surround View software and +associated data and documentation may only be used for evaluation purposes and +for demonstration to third parties in integrated form on a board package +containing an NXP S32V234 device. Licensee may not distribute or sublicense the +TES software. Your license to the TES software may be terminated at any time +upon notice. + +Vivante: Distribution of Vivante software must be a part of, or embedded +within, Authorized Systems that include a Vivante Graphics Processing Unit. diff --git a/Licenses/COPYING-BSD-3 b/Licenses/COPYING-BSD-3 new file mode 100644 index 0000000..de461d9 --- /dev/null +++ b/Licenses/COPYING-BSD-3 @@ -0,0 +1,33 @@ +The BSD 3 Clause License + +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. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. +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. diff --git a/Licenses/LICENSE-2.0.txt b/Licenses/LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Licenses/LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/Licenses/MICROEJ_SDK_EULA.txt b/Licenses/MICROEJ_SDK_EULA.txt new file mode 100644 index 0000000..f8499e5 --- /dev/null +++ b/Licenses/MICROEJ_SDK_EULA.txt @@ -0,0 +1,38 @@ +This Software is provided both as Executable Software (code compiled AND +delivered by MicroEJ Corp.) and Software Source Code. + +If YOU are a MicroEJ SDK licensee, YOU can choose between the following +open-source license and Your MicroEJ SDK LICENSE (MicroEJ SDK EULA) : + +The Executable Software can be, at your option, subject to MicroEJ SDK EULA. + +The source code will always be subject to the following license. + +For the avoidance of doubt, any modification of the source code, or any +addition to the Software will break the warranties and will exempt MicroEJ Corp. +from any obligation arising under any specific agreement . +----------------------------------------------------------------------------- + +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* 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. +* Neither the name of MicroEJ Corp. nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS AND CONTRIBUTORS 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. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..afaf9e8 --- /dev/null +++ b/Makefile @@ -0,0 +1,117 @@ +# +# Copyright 2023-2024 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# +MODULE_REPOSITORY_SETTINGS_FILE?=$(MODULE_REPOSITORY_SETTINGS_FILE_VAR) +ECLIPSE_HOME=$(ECLIPSE_HOME_VAR) + +ifeq ($(OS),Windows_NT) +MICROEJ_SEC=cmd /c "echo jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize ^< 1024, \ + DSA keySize ^< 1024, include jdk.disabled.namedCurves > javasec.prop" +else +MICROEJ_SEC=echo "jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ + DSA keySize < 1024, include jdk.disabled.namedCurves" > javasec.prop +endif + +S2S_PORT=5555 +S2S_TTY ?= /dev/ttyACM0 + +ifeq ($(OS),Windows_NT) +BASE_DIR=${CURDIR} +else +BASE_DIR=$(shell pwd) +endif + +define del_file + $(if $(filter $(OS),Windows_NT),$(if $(wildcard $(1)),cmd /c DEL /f /q $(subst /,\\,$(1)),),rm -f $(1)) +endef + +define del_dir + $(if $(filter $(OS),Windows_NT),$(if $(wildcard $(1)),cmd /c RD /s /q $(subst /,\\,$(1)),),rm -fr $(1)) +endef + + +BSP_DIR=$(BASE_DIR)/bsp +PLAT_DIR=$(BASE_DIR)/microej/MCXN947-frdm_platform-CM4hardfp_GCC48-1.0.0 +APP_DIR=$(BASE_DIR)/microej/apps +MOCK_DIR=$(BASE_DIR)/microej/mock +FP_DIR=$(BASE_DIR)/microej/front-panel +CONF_DIR=$(BASE_DIR)/microej/vee-port-configuration +VAL_DIR=$(BASE_DIR)/microej/validation + +TEST_DIR.java.test.core=$(VAL_DIR)/core/java-testsuite-runner-core +TEST_DIR.java.test.fs=$(VAL_DIR)/fs/java-testsuite-runner-fs +TEST_DIR.java.test.gpio=$(VAL_DIR)/gpio/java-testsuite-runner-gpio +TEST_DIR.java.test.net=$(VAL_DIR)/net/java-testsuite-runner-net +TEST_DIR.java.test.security=$(VAL_DIR)/security/java-testsuite-runner-security +TEST_DIR.java.test.ssl=$(VAL_DIR)/ssl/java-testsuite-runner-ssl + +VALIDATIONS ?= core fs gpio net security ssl + +ifeq ($(ECLIPSE_HOME_VAR),) +$(error Define ECLIPSE_HOME_VAR to e.g. ~/MicroEJ/MicroEJ-SDK-21.11/rcp/) +endif + +ifeq ($(strip $(VERBOSE)),1) + JAVA_VERBOSE=-v +endif + +ifeq ($(strip $(QUIET)),1) + JAVA_VERBOSE=-q +endif + +ifeq ($(strip $(CMAKE_OPTS)),) + OPT='CMAKE_OPTS=-DENABLE_NET=1 -DENABLE_SEC=1' +endif + +ifeq ($(strip $(PUBLISH)),1) + PUBLISH_ARTIFACTS=-Dskip.publish=false + PUBLISH_MODE=release + MODULE_REPOSITORY_SETTINGS= +else + PUBLISH_ARTIFACTS= + PUBLISH_MODE= +endif + +USAGE?=eval +CMAKE_OPTS?= + +ifneq ($(MODULE_REPOSITORY_SETTINGS_FILE),) + MODULE_REPOSITORY_SETTINGS=--module-repository-settings-file=$(MODULE_REPOSITORY_SETTINGS_FILE) +endif + +JAVAZIP ?= + +MAIN ?= + +nxpvee-ui.prj: +nxpvee-validation.prj: + +MAIN.nxpvee-ui.java.app=com.nxp.simpleGFX.SimpleGFX + +PROJS = nxpvee-ui + +include Makefile.inc + +help: + @echo "npa-mcxn947-frdm build system:" + @echo "" + @echo "Valid targets are:" + @echo " nxpvee-ui.prj build complete UI project" + @echo " nxpvee-ui-clean clean UI project" + @echo " nxpvee-ui-flash flash board using J-Link" + @echo " nxpvee-ui-flash_cmsisdap flash board using CMSIS" + @echo " nxpvee-ui-gdb debug UI project using gdb and J-Link" + @echo " nxpvee-ui-gdb_cmsisdap debug UI project using gdb and CMSIS" + @echo " nxpvee-ui-java_run run java simulation" + @echo " nxpvee-ui-java_rebuild rebuild java app" + @echo " nxpvee-validation.prj compile and run validation" + @echo "" + @echo "Valid options are:" + @echo " S2S_TTY set validation serial port (e.g. /dev/ttyACM0)" + @echo " VALIDATIONS='[option]+' overrides validation projects to be run {core, fs, net, security, ssl}" + @echo " VERBOSE=1 compile in verbose mode" + @echo " QUIET=1 compile in quiet mode" + @echo " USAGE=[eval|prod] compile in eval or prod" + @echo " MAIN=com.nxp... overrides java MAIN [com.nxp.simpleGFX.SimpleGFX, com.nxp.aiSample.AiMain]" diff --git a/Makefile.inc b/Makefile.inc new file mode 100644 index 0000000..d689f1f --- /dev/null +++ b/Makefile.inc @@ -0,0 +1,151 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ifeq ($(OS),Windows_NT) +S2SEXE=$(BSP_DIR)/projects/common/scripts/s2s.bat +LINK=&& +TOUCH=cmd /c type nul > +EXPORT=cmd /c SET +UNZIP=tar -xf +FIND_JAVA_FILES_IN_APP_DIR=$(shell cmd /c dir /s /b "$(subst /,\,$(APP_DIR))\*.java") +else +S2SEXE=$(BSP_DIR)/projects/common/scripts/s2s.sh +LINK=; +TOUCH=touch +EXPORT=export +UNZIP=unzip +FIND_JAVA_FILES_IN_APP_DIR=$(shell find $(APP_DIR) -name "*.java") +endif + +.PRECIOUS: .java.fp .java.mock .java.configuration .%.java.app + +.java.fp: $(FP_DIR)/module.ivy + cd $(FP_DIR) $(LINK) $(MICROEJ_BUILDKIT_PATH_VAR)/bin/mmm publish \ + -Declipse.home="$(ECLIPSE_HOME)" \ + -Dcom.microej.platformbuilder.architecture.usage=$(USAGE) \ + $(MODULE_REPOSITORY_SETTINGS) \ + $(JAVA_VERBOSE) + $(TOUCH) $@ + +.java.mock: + cd $(MOCK_DIR) $(LINK) $(MICROEJ_BUILDKIT_PATH_VAR)/bin/mmm publish \ + -Declipse.home="$(ECLIPSE_HOME)" \ + -Dcom.microej.platformbuilder.architecture.usage=$(USAGE) \ + $(MODULE_REPOSITORY_SETTINGS) \ + $(JAVA_VERBOSE) + $(TOUCH) $@ + +.java.configuration: $(CONF_DIR)/module.ivy + cd $(CONF_DIR) $(LINK) $(MICROEJ_BUILDKIT_PATH_VAR)/bin/mmm publish $(PUBLISH_MODE) \ + $(PUBLISH_ARTIFACTS) \ + -Declipse.home="$(ECLIPSE_HOME)" \ + -Dcom.microej.platformbuilder.architecture.usage=$(USAGE) \ + $(MODULE_REPOSITORY_SETTINGS) \ + $(JAVA_VERBOSE) + $(TOUCH) $@ + +.java.test.s2s: + $(S2SEXE) $(S2S_TTY) $(S2S_PORT) & + +javasec.prop : + $(MICROEJ_SEC) + +$(addprefix .java.test.,$(VALIDATIONS)): javasec.prop + cd $(TEST_DIR$@) $(LINK) $(EXPORT) TEST_TYPE="ARMGCC" $(EXPORT) CMAKE_OPTS=$(OPT) $(LINK) $(MICROEJ_BUILDKIT_PATH_VAR)/bin/mmm publish \ + -Declipse.home="$(ECLIPSE_HOME)" \ + $(MODULE_REPOSITORY_SETTINGS) \ + -Dcom.microej.platformbuilder.architecture.usage=$(USAGE) \ + -Dplatform-loader.target.platform.dir=$(PLAT_DIR)/source \ + -Ddeploy.bsp.root.dir=$(BSP_DIR) \ + -Dlaunch.properties.jvm="-Djava.security.properties=$(BASE_DIR)/javasec.prop" \ + -D"local.repo.url=$(BASE_DIR)/test_results/" \ + -Dplatform-launcher.platform.dir=$(PLAT_DIR)/source $(JAVA_VERBOSE) + +.%.java.app: javasec.prop $(APP_DIR)/module.ivy $(FIND_JAVA_FILES_IN_APP_DIR) + cd $(APP_DIR) $(LINK) $(MICROEJ_BUILDKIT_PATH_VAR)/bin/mmm publish \ + -Declipse.home="$(ECLIPSE_HOME)" \ + $(MODULE_REPOSITORY_SETTINGS) \ + -Dcom.microej.platformbuilder.architecture.usage=$(USAGE) \ + -Dplatform-loader.target.platform.dir=$(PLAT_DIR)/source \ + -Dplatform-launcher.platform.dir=$(PLAT_DIR)/source \ + -Dapplication.main.class=$(if $(MAIN),$(MAIN),$(MAIN$@)) \ + -Dlaunch.properties.jvm="-Djava.security.properties=$(BASE_DIR)/javasec.prop" \ + -Ddeploy.bsp.root.dir=$(BSP_DIR) $(JAVA_VERBOSE) + $(call del_file,.*.java.app) + $(TOUCH) $@ + +nxpvee-validation.prj: clean .java.fp .java.mock .java.configuration .java.test.s2s $(addprefix .java.test.,$(VALIDATIONS)) + echo "done" + + +%.prj: .java.fp .java.mock .java.configuration .%.java.app + make -C $(BSP_DIR)/projects/$(basename $@)/sdk_makefile $(OPT) + +$(addsuffix -javazip,$(PROJS)): + make clean + cd $(BSP_DIR)/projects/microej; $(UNZIP) $(JAVAZIP) + make -C $(BSP_DIR)/projects/$(@:%-javazip=%)/sdk_makefile + + +$(addsuffix -flash,$(PROJS)): + make $(@:%-flash=%).prj + make -C $(BSP_DIR)/projects/$(@:%-flash=%)/sdk_makefile flash + +$(addsuffix -flash_cmsisdap,$(PROJS)): + make $(@:%-flash_cmsisdap=%).prj + make -C $(BSP_DIR)/projects/$(@:%-flash_cmsisdap=%)/sdk_makefile flash_cmsisdap + +$(addsuffix -gdb,$(PROJS)): + make $(@:%-gdb=%).prj + make -C $(BSP_DIR)/projects/$(@:%-gdb=%)/sdk_makefile gdb + +$(addsuffix -gdb_cmsisdap,$(PROJS)): + make $(@:%-gdb_cmsisdap=%).prj + make -C $(BSP_DIR)/projects/$(@:%-gdb_cmsisdap=%)/sdk_makefile gdb_cmsisdap + +$(addsuffix -java_run,$(PROJS)): .java.fp .java.mock .java.configuration + cd $(APP_DIR) $(LINK) $(MICROEJ_BUILDKIT_PATH_VAR)/bin/mmm run \ + -Declipse.home="$(ECLIPSE_HOME)" \ + $(MODULE_REPOSITORY_SETTINGS) \ + -Dcom.microej.platformbuilder.architecture.usage=$(USAGE) \ + -Dplatform-loader.target.platform.dir=$(PLAT_DIR)/ \ + -Dapplication.main.class=$(if $(MAIN),$(MAIN),$(MAIN.$(@:%-java_run=%).java.app)) \ + -Dplatform-launcher.platform.dir=$(PLAT_DIR)/source $(JAVA_VERBOSE) + +$(addsuffix -java_rebuild,$(PROJS)): .java.fp .java.mock .java.configuration + $(call del_file,.*.java.app) + make .$(@:%-java_rebuild=%).java.app + +$(addsuffix -clean,$(PROJS)): + make -C $(BSP_DIR)/projects/$(@:%-clean=%)/sdk_makefile clean + make -C $(BSP_DIR)/projects/$(@:%-clean=%)/sdk_makefile distclean + $(call del_file,.*.java.app) + $(call del_file,.java.*) + $(call del_file,javasec.prop*) + $(call del_dir,$(PLAT_DIR)/build/) + $(call del_dir,$(PLAT_DIR)/source/) + $(call del_dir,$(CONF_DIR)/dropins/include) + $(call del_dir,$(CONF_DIR)/dropins/javaLibs) + $(call del_dir,$(CONF_DIR)/dropins/mocks) + $(call del_file,$(CONF_DIR)/dropins/workbenchExtension_launchScriptFramework.jar) + $(call del_file,$(CONF_DIR)/dropins/imagegenerator-vectorimage.jar) + $(call del_file,$(CONF_DIR)/dropins/license-checker.jar) + $(call del_dir,$(CONF_DIR)/target~/) + $(call del_dir,$(FP_DIR)/bin/) + $(call del_dir,$(FP_DIR)/lib/) + $(call del_dir,$(FP_DIR)/target~/) + $(call del_dir,$(APP_DIR)/bin/) + $(call del_dir,$(APP_DIR)/filesystem/) + $(call del_dir,$(APP_DIR)/src-adpgenerated/) + $(call del_dir,$(APP_DIR)/target~/) + $(call del_dir,$(BSP_DIR)/projects/microej/platform/) + $(call del_dir,$(MOCK_DIR)/bin/) + $(call del_dir,$(MOCK_DIR)/target~/) + $(call del_dir,$(VAL_DIR)/core/java-testsuite-runner-core/target~/) + $(call del_dir,$(BSP_DIR)/projects/nxpvee-ui/mcuide/Release/) + +clean: $(addsuffix -clean,$(PROJS)) + echo "clean" diff --git a/README.md b/README.md new file mode 100644 index 0000000..e30f2f8 --- /dev/null +++ b/README.md @@ -0,0 +1,801 @@ +- [NXP Platform Accelerator for MCXN947 Freedom board v1.0.0](#nxp-platform-accelerator-for-mcxn947-freedom-board-v100) + - [MicroEJ SDK 6](#microej-sdk-6) + - [MicroEJ SDK 5](#microej-sdk-5) + - [VEE Port Specifications](#vee-port-specifications) + - [Requirements](#requirements) + - [Directory structure](#directory-structure) + - [Preliminary steps](#preliminary-steps) + - [Get West](#get-west) + - [Get the MicroEJ SDK](#get-the-microej-sdk) + - [Get Visual Studio Code](#get-visual-studio-code) + - [Get GNU ARM Embedded Toolchain](#get-gnu-arm-embedded-toolchain) + - [Fetch the source code](#fetch-the-source-code) + - [West : `PermissionError: \[WinError 5\] Access is denied`](#west--permissionerror-winerror-5-access-is-denied) + - [MicroEJ IDE project setup](#microej-ide-project-setup) + - [Import the project in a new workspace](#import-the-project-in-a-new-workspace) + - [Build the VEE Port](#build-the-vee-port) + - [Build and run applications using the MicroEJ SDK IDE](#build-and-run-applications-using-the-microej-sdk-ide) + - [Build and run the applications in simulation mode](#build-and-run-the-applications-in-simulation-mode) + - [Build and run applications on your MCXN947 Freedom board](#build-and-run-applications-on-your-mcxn947-freedom-board) + - [Get an evaluation license](#get-an-evaluation-license) + - [Build the applications for target](#build-the-applications-for-target) + - [Build the firmware for target hardware using VS Code](#build-the-firmware-for-target-hardware-using-vs-code) + - [Switching to a production license](#switching-to-a-production-license) + - [Alternative: build and run from command line](#alternative-build-and-run-from-command-line) + - [Requirements for building from command line](#requirements-for-building-from-command-line) + - [Populate a Build Kit](#populate-a-build-kit) + - [Using default evaluation license](#using-default-evaluation-license) + - [Needed Environment variables](#needed-environment-variables) + - [Explore available options (works on Linux)](#explore-available-options-works-on-linux) + - [compile and flash](#compile-and-flash) + - [Compilation defaults](#compilation-defaults) + - [compile with just NET support enabled](#compile-with-just-net-support-enabled) + - [compile Ai demo](#compile-ai-demo-1) + - [debug](#debug) + - [Ninja](#ninja) + - [Compile Release image](#compile-release-image) + - [Compile using production license](#compile-using-production-license) + - [Compiling using west](#compiling-using-west) + - [Tutorial: Using native C functions from the high level application](#tutorial-using-native-c-functions-from-the-high-level-application) + - [Declaring and using native functions in the Java world](#declaring-and-using-native-functions-in-the-java-world) + - [Implementing the native functions in C world](#implementing-the-native-functions-in-c-world) + - [Implementing a mockup of the native functions for the simulator](#implementing-a-mockup-of-the-native-functions-for-the-simulator) + - [Get familiar with MICROEJ](#get-familiar-with-microej) + - [Examples](#examples) + - [MICROEJ Documentation](#microej-documentation) + - [Troubleshooting](#troubleshooting) + - [License Error when building application](#license-error-when-building-application) +# NXP Platform Accelerator for MCXN947 Freedom board v1.0.0 +This project is used to build NXP Platform Accelerator for the [MCXN947 Freedom board](https://www.nxp.com/design/design-center/development-boards/general-purpose-mcus/frdm-development-board-for-mcx-n94-n54-mcus:FRDM-MCXN947) with a display panel [LCD_PAR_S035](https://www.nxp.com/design/design-center/development-boards/general-purpose-mcus/3-5-480x320-ips-tft-lcd-module:LCD-PAR-S035). + +![frdm-mcxn947](Documentation/pictures/MCXN947/frdm-mcxn947.jpg) +![lcd-par-s035](Documentation/pictures/MCXN947/lcd-par-s035.jpg) + +NXP Platform Accelerator a VEE (Virtual Execution Environment) and provides a hardware abstraction to develop applications in high-level programming languages such as Java. + +NXP Platform Accelerator is built upon [MicroEJ technology](https://www.microej.com/product/vee/). + +This release includes: + +* MCXN947 Freedom board simulator to develop VEE applications and test them on a host PC + * The simulator program has a graphic display of the EVK board and its LCD panel +* The necessary recipes to embed the VEE architecture for GCC +* Various [Foundation Libraries](https://docs.microej.com/en/latest/ApplicationDeveloperGuide/libraries.html) to provide high level libraries to developers +* Notable Foundation Libraries part of this release are: + * [MicroUI](https://docs.microej.com/en/latest/ApplicationDeveloperGuide/UI/MicroUI/index.html#section-app-microui) to create user interfaces + + + * [Networking](https://docs.microej.com/en/latest/ApplicationDeveloperGuide/networkingFoundationLibraries.html) + + + * [AI](https://forge.microej.com/ui/native/microej-developer-repository-release/com/nxp/api/ai/1.0.0/): AI / Machine Learning library based on TensorFlowLite + + + * [GPIO](https://forge.microej.com/ui/native/microej-developer-repository-release/com/nxp/api/gpio/1.0.0/) + +* [MCUXpresso SDK](https://mcuxpresso.nxp.com/en/welcome) 2.14.0 MCXNx4x for MCXN947 Freedom board +* [FreeRTOS](https://www.freertos.org/index.html) version 10.5.0 +* Sample applications demonstrating NXP VEE: + + * SimpleGFX: draw moving NXP coloured boxes using MicroUI + + + + * AI_Cifarnet_Demo: runs an inference of CifarNet quantized TensorFlow model on sample images + + + * Compatible with the [MQTT Demo application](https://repository.microej.com/packages/documentation/cinterion-vee/1.8/getting-started/demo/index.html) of MicroEJ + +* [Mock](https://docs.microej.com/en/latest/PlatformDeveloperGuide/mock.html) support with Java stub implementations to mimick C native functions. Thanks to this mock support, the SimpleGFX application can smoothly run on the simulator + +## MicroEJ SDK 6 + +NXP Platform Accelerator is built on MicroEJ technology. + +MicroEJ SDK 6 is the latest available MicroEJ SDK. +The SDK 6 uses Gradle plugin to compile and package MicroEJ modules. +It allows the user to use his favourite IDE such as Android Studio or IntelliJ IDEA (see [the list of supported IDE](https://docs.microej.com/en/latest/SDK6UserGuide/install.html#install-the-ide)). + +SDK 6 is currently limited to the build, test and simulation of **Applications and Add-on Libraries** (see [Scope and Limitations](https://docs.microej.com/en/latest/SDK6UserGuide/limitations.html#sdk-6-limitations) for more information). +If you need other features, such as **developping a VEE Port**, you have to use the SDK 5. + +If you are an application developer only and do not need to make changes to the VEE Port, you can use the SDK 6. Please click on the button below to access to the SDK 6 Getting Started on the MCXN947 Freedom board. + +[![sdk6-documentation](Documentation/pictures/common/sdk6-button.png)](https://docs.microej.com/en/latest/SDK6UserGuide/gettingStartedIMXRT1170.html) + +## MicroEJ SDK 5 + +If you want to modify the VEE Port, make changes to low level source code, please use SDK 5 and continue following this README. + + +## VEE Port Specifications +The architecture version is ```8.1.0```. + +This VEE Port provides the following Foundation Libraries: + +|Foundation Library|Version| +|------------------|-------| +|AI |1.0| +|BON |1.4| +|DEVICE |1.2| +|DRAWING |1.0| +|EDC |1.3| +|FS |2.1| +|GPIO |1.0| +|MICROUI |3.1| +|NET |1.1| +|SECURITY |1.4| +|SNI |1.4.0| +|SSL |2.2| +|TRACE |1.1| + + +## Requirements +* PC with Windows 10 or higher, or Linux (tested on Debian 11) + * Note for Mac users: this documentation does not cover Mac usage, however it is supported by the MicroEJ tools. If you are interested in Mac support, please [contact MicroEJ](https://www.microej.com/contact/#form_2). +* Java JDK 11 see [Get the MicroEJ SDK](#get-the-microej-sdk) section +* [West](https://docs.zephyrproject.org/latest/develop/west/install.html), a meta-tool to handle git dependencies +* Internet connection to [MicroEJ Central Repository](https://developer.microej.com/central-repository/) +* MCXN947 Freedom board board, available [here](https://www.nxp.com/design/design-center/development-boards/general-purpose-mcus/frdm-development-board-for-mcx-n94-n54-mcus:FRDM-MCXN947) +* LCD_PAR_S035 display panel, available [here](https://www.nxp.com/design/design-center/development-boards/general-purpose-mcus/3-5-480x320-ips-tft-lcd-module:LCD-PAR-S035) +* Optionally: J-Link Debugger to flash the software + + +## Directory structure +``` +[...] +├── bsp +│ └── projects +│ ├── common +│ ├── microej +│ └── nxpvee-ui +├── CHANGELOG.md +├── cmake +├── CMakeLists.txt +├── Documentation +├── Licenses +├── LICENSE.txt +├── Makefile +├── Makefile.inc +├── microej +│ ├── apps +│ ├── front-panel +│ ├── MCXN947-frdm_platform-CM4hardfp_GCC48-1.0.0 +│ ├── mock +│ ├── validation +│ └── vee-port-configuration +├── README.md +├── scripts +├── SCR-nxpvee-mcxn947-frdm.txt +└── west.yml +``` + + +## Preliminary steps + +### Get West +[West](https://docs.zephyrproject.org/latest/develop/west/index.html) is Zephyr's meta-tool that supports multiple repository management. Examples are provided later in this documentation on how to use West to fetch the code and dependencies. + +Install West by following [Installing west](https://docs.zephyrproject.org/latest/develop/west/install.html) instructions. + +### Get the MicroEJ SDK +The MICROEJ SDK is an Eclipse-based IDE used to build the VEE Port and the high-level applications. The SDK can be used to run the MCXN947 Freedom board simulator. + +The MICROEJ SDK requires Java JDK. JDK version [depends on the MICROEJ SDK version](https://docs.microej.com/en/latest/SDKUserGuide/systemRequirements.html). + +* Install the JDK. You can download it on the [Java SE 11](https://www.oracle.com/java/technologies/downloads/#java11) page +* Install MICROEJ SDK 23.07. Please refer to [Download and Install – MicroEJ Documentation](https://docs.microej.com/en/latest/SDKUserGuide/installSDKDistributionLatest.html#) and [Installer Repository](https://repository.microej.com/packages/SDK/23.07/) + +This release has been tested with MicroEJ SDK 23.07 and Java JDK 11. + +### Get Visual Studio Code +VS Code is an IDE used to build, flash and debug embedded projects. + +In this VEE Port release, VS Code is used to build the firmware that will be flashed to target. VS Code project uses the VEE Port and high level applications built by the MicroEJ SDK. + +* You can download VS Code IDE [here](https://code.visualstudio.com/download). +* Start VS Code and install the [MCUXpresso for VS Code](https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-for-visual-studio-code:MCUXPRESSO-VSC?tid=vanMCUXPRESSO-VSC) extension package. +* Install the [MCUXpresso VS Code package dependencies](https://github.com/nxp-mcuxpresso/vscode-for-mcux/wiki/Dependency-Installation) to support the full development flow. + +### Get GNU ARM Embedded Toolchain +To build an image that runs on target, you need a Cortex-M toolchain. +The [GNU ARM Embedded Toolchain](https://developer.arm.com/downloads/-/gnu-rm) is used to validate this release. + +**Toolchain for Linux**: [gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2](https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2?rev=78196d3461ba4c9089a67b5f33edf82a&hash=D484B37FF37D6FC3597EBE2877FB666A41D5253B) + +**Toolchain for Windows**: [gcc-arm-none-eabi-10.3-2021.10-win32.exe](https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-win32.exe?rev=29bb46cfa0434fbda93abb33c1d480e6&hash=3C58D05EA5D32EF127B9E4D13B3244D26188713C) + +Once installed, the following environment variable must be set to point to the toolchain directory: + +Linux: + +* Open ` ~/.bashrc` file. +* Add the following line at the end of the file: + +``` +export ARMGCC_DIR=/opt/gcc-arm-none-eabi-10.3-2021.10/ +``` + +Windows: + +* Open the `Edit the system environment variables` application on Windows. +* Click on the `Environment Variables…` button. +* Click on the `New…` button under the `User variables` section. +* Set `Variable` Name to `ARMGCC_DIR`. +* Set `Variable Value` to the toolchain directory (e.g. `C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10`). +* Click on the `Ok` button until it closes `Edit the system environment variables` application. + + + + +## Fetch the source code + +On Windows, fetching the source code may trigger the following fatal error: +```error: unable to create file [...]: Filename too long.``` +To avoid this, git configuration needs to be updated to handle long file names: + +Start Git Bash as Administrator. + +Run following command: +```git config --system core.longpaths true``` + +Clone the repository with the following command: + +``` +mkdir  nxp-vee-mcxn947-frdm +cd nxp-vee-mcxn947-frdm +west init -m https://github.com/nxp-mcuxpresso/nxp-vee-mcxn947-frdm.git . +west update +``` +you will get + +``` +.west nxp-vee-mcxn947-frdm +``` +### West : `PermissionError: [WinError 5] Access is denied` + +If you get the error `PermissionError: [WinError 5] Access is denied`, please consider the following procedure : + +``` +rm .west +cd nxp-vee-mcxn947-frdm +west init -l +cd .. +west update +``` + +## MicroEJ IDE project setup +### Import the project in a new workspace +Launch MicroEJ SDK and create a blank workspace. + +Import the cloned repository as an existing project: + +![Import...](Documentation/pictures/common/sdk_import.png) + +![Existing Projects Into Workspace](Documentation/pictures/common/sdk_existing_project.png) + +Then select all projects from the repository. + +![Projects List](Documentation/pictures/MCXN947/sdk_projects_list.png) + +The package explorer view should look like this: + +![Package Explorer](Documentation/pictures/MCXN947/sdk_package_explorer.png) + +### Build the VEE Port +The VEE Port for the board is the first thing to build with the IDE. +For demonstration purposes, one of the release examples uses a mockup (more details follow in the native functions description). +The mockup is a dependency of the VEE Port and must therefore be built beforehand. + + +#### Build the mockup +Right click on the mockup project and select `Build Module`: + +![Build mockup](Documentation/pictures/MCXN947/sdk_build_mock.png) + +#### Build the VEE Port +Once the mockup dependency is resolved, the VEE Port can be built by using [VEE Port Build](https://docs.microej.com/en/latest/VEEPortingGuide/platformCreation.html#platform-build) instructions. +Right-click on the configuration project and select `Build Module`: + +![Build platform](Documentation/pictures/MCXN947/sdk_build_platform.png) + +Building the platform will populate the initally empty `MCXN947-frdm_platform-CM4hardfp_GCC48-1.0.0` project which will be used to build VEE applications. +Under the `source` folder of the VEE Port, you will find the following files: +* The C header files of the native needed by the VEE Port libraries are located in the `include` folder. +* The Java API of the VEE Port libraries is located in the `javaAPIS` folder. +* The jar files of the VEE Port libraries are located in the `javaLibs` folder. +* The Simulation files are located in the `S3` and `mocks` folders. +* The VEE core, the MicroJVM, and some tools. + +## Build and run applications using the MicroEJ SDK IDE + +This release comes with an example VEE application. + + +Application `SimpleGFX` displays three moving rectangles using the [MicroUI API](https://docs.microej.com/en/latest/ApplicationDeveloperGuide/UI/MicroUI/index.html#section-app-microui). The coordinates of the rectangles are calculated in C native functions. + + + + +### Build and run the applications in simulation mode +To run applications in simulation mode, right-click on the apps project and select `Run As -> MicroEJ Application`: + +![Run As MicroEJ Application](Documentation/pictures/MCXN947/sdk_run_as_microej_app.png) + + +To run the application in simulation mode, select the mode _(SIM)_: + + +![Choose build mode](Documentation/pictures/MCXN947/sdk_choose_app_mode.png) + + +Here is the `SimpleGFX` application running in simulation: + +![Simple GFX](Documentation/pictures/MCXN947/sdk_sim_simple.png) + + +## Build and run applications on your MCXN947 Freedom board + +### Get an evaluation license +A license is required to build an embedded application. + +A MicroEJ license is required to build high-level applications and the VEE Port for target hardware. + +Evaluation licenses can be obtained for free. Please follow [the instructions from MicroEJ](https://docs.microej.com/en/latest/SDKUserGuide/licenses.html#evaluation-license). + +With an evaluation license, you can build high-level applications with no limitation in simulation mode. However, applications built with an evaluation license will run for a limited time on target hardware. + +Evaluation licenses must be renewed periodically (every month). + +**Important note**: applications built with an evaluation license will freeze after a random period of time. A production license is necessary to have a fully working application on the target. + + +### Build the applications for target +With the MicroEJ SDK IDE, simply run the application the same way than [in simulation](#build-and-run-the-applications-in-simulation-mode) but by choosing the mode _(EMB)_. + +#### Output of the build +The build will produce two artifacts: + +* *microejapp.o*: the linked managed code application. +* *microejruntime.a*: the VEE core. + +These artifacts are copied to the BSP project in the directory `projects/microej/platform/lib`. + +### Build the firmware for target hardware using VS Code +#### vscode full solution compilation +vscode can compile, using cmake the full solution +Java application and the bsp +in order to do that you need to follow below instuctions to + +- [Populate a Buildkit](#populate-a-build-kit) +- Export these two variables + +on Linux +``` +export MICROEJ_BUILDKIT_PATH_VAR=${HOME}/microej/BuildKit +export ECLIPSE_HOME_VAR=${HOME}/MicroEJ/MicroEJ-SDK-21.11/rcp/ +``` + +On Windows +* Open the `Edit the system environment variables` application on Windows. +* Click on the `Environment Variables…` button. +* Click on the `New…` button under the `User variables` section. +* Set `Variable` Name to `MICROEJ_BUILDKIT_PATH_VAR`. +* Set `Variable Value` to the BuildKitdirectory +* Click on the `Ok` button until it closes `Edit the system environment variables` application. + +same for `ECLIPSE_HOME_VAR` + +#### vscode just bsp compilation +if you prefer to just build the BSP +change + +``` + "cmake.sourceDirectory": "${workspaceFolder}/", + "cmake.buildDirectory": "${workspaceFolder}/build/${buildType}", +``` +into +``` + "cmake.sourceDirectory": "${workspaceFolder}/bsp/projects/nxpvee-ui/armgcc", + "cmake.buildDirectory": "${workspaceFolder}/bsp/projects/nxpvee-ui/armgcc/build/${buildType}", +``` + +Once the application is ready, the firmware can be built using a C toolchain for Cortex-M. + +#### Load the project into VS Code +Launch VS Code IDE and click on `File -> Add Folder to Workspace...` + +![Add Folder to Workspace](Documentation/pictures/common/vscode_load_project.jpg) + +Navigate to the nxp-vee-mcxn947-frdm path then click `Add`. + +From here you can compile and debug the project as any other C project. + +To do so you need to configure then build the CMake project by following the steps below: + +#### Scan for kits to locate all available toolchains +Open the Command Palette (`CTRL + SHIFT + p`) and run `CMake: Scan for kits`. + +![VScode scan for kits](Documentation/pictures/common/vscode_scan_for_kits.jpg) + +#### Select the toolchain that will build the project +Open the Command Palette (`CTRL + SHIFT + p`) and run `CMake: Select a kit` + +![VScode select a kit](Documentation/pictures/common/vscode_select_a_kit-1.jpg) + +Choose the compiler `armgcc` in the path of your project. + +![VScode select gcc compiler](Documentation/pictures/common/vscode_select_a_kit-2.jpg) + +#### Select a build variant +Open the Command Palette (`CTRL + SHIFT + p`) and run `CMake: Select variant` to select the build mode you wish to use. +By default, you can select `flexspi_nor_sdram_debug` variant. + +![VScode select build variant](Documentation/pictures/common/vscode_select_variant.jpg) + +#### Configure the project +Open the Command Palette (`CTRL + SHIFT + p`) and run `CMake: Configure`. + +![VScode select configure](Documentation/pictures/common/vscode_select_configure.jpg) + +#### Configure the bsp features +Edit settings.json and enable the desired feature +``` +{ +... + "cmake.configureArgs": [ + "-DENABLE_NET=0", + "-DENABLE_AI=0", + "-DJMAIN=com.nxp.simpleGFX.SimpleGFX" + ] +} +``` +##### Enable NET +Set +``` +"-DENABLE_NET=1", +``` + + +##### Compile AI Demo +Set +``` +"-DENABLE_AI=1", +"-DJMAIN=com.nxp.aiSample.AiMain" +``` + + +#### Build the project +Open the Command Palette (`CTRL + SHIFT + p`) and run `CMake: Build`. + +![VScode build project](Documentation/pictures/common/vscode_select_build.jpg) + +You can connect VS Code to the board using the Serial Link USB or using a SEGGER J-Link probe. +Follow the [Board Hardware User Guide](#board-setup) for more information on how to connect the different debuggers. + +Debug session can be started by pressing the `F5` key. + +It is also possible to build and debug the project via the MCUXpresso plugin: + +Right click on the project nxp-vee-rt595, then: + +* `Build Selected` to compile +* `Debug` to debug + +![VScode MCUXpresso build and debug project](Documentation/pictures/common/vscode_mcuxpr_build_debug.jpg) + +Once the firmware is flashed, you should see the application running on the target. + +#### Note: +In case of connection issue to the target, reset the debug probe selection via the MCUXpresso plugin: + +* Select the MCUXpresso plugin in the left banner +* Right-click on the project name and select `Reset Probe Selection` +* Start the debug again + +![VScode MCUXpresso reset probe selection](Documentation/pictures/common/vscode_reset_probe_selection.jpg) + + + +## Switching to a production license +To switch to a production license, please contact your NXP representative. + +## Alternative: build and run from command line +This has only been tested on Linux. + +A set of makefiles is provided to build either the whole project (VEE Port, high level application, firmware) or the final firmware from command line instead of using the MicroEJ / MCUXpresso IDE. +This can be useful for continuous integration or to get a more automated environment during development. + +To access the top level makefile: +``` +cd nxp-vee-mcxn947-frdm +``` + +### Requirements for building from command line + +#### C toolchain +Make sure that the `ARMGCC_DIR` environment variable is set to the toolchain directory. +If not, you must add it: + +Linux: +``` +export ARMGCC_DIR=/opt/gcc-arm-none-eabi-10.3-2021.10/ +``` + +#### CMake +The build system used to generate the firmware is based on CMake. + +Linux: to install CMake on a Debian based distro, run: +``` +sudo apt install cmake +``` + +#### Make +Linux: to install GNU Make on a Debian based distro, run: +``` +sudo apt install make +``` + +### Populate a Build Kit +It is necessary to export a Build Kit from the MicroEJ SDK IDE. This Build Kit is used by the makefile to build the VEE Port and the high level applications. + +The Build Kit is bundled with the SDK and can be exported using the following steps: +``` + Select File > Export > MicroEJ > Module Manager Build Kit, + Choose an empty Target directory, `i.e. ${HOME}/microej/BuildKit ` + Click on the Finish button. +``` +### Using default evaluation license +Please follow [Install the License Key](https://docs.microej.com/en/latest/SDKUserGuide/licenses.html#install-the-license-key) to be able to use make with an evaluation key + +### Needed Environment variables +In order to compile correctly you will need to export + +``` +export MICROEJ_BUILDKIT_PATH_VAR=${HOME}/microej/BuildKit +export ECLIPSE_HOME_VAR=${HOME}/MicroEJ/MicroEJ-SDK-21.11/rcp/ +``` + +you can also specify a partial repository, when needed (for example if you need libraries that are not yet public) +``` +export MODULE_REPOSITORY_SETTINGS_FILE_VAR=${HOME}/microej/microej-partial-repository/ivysettings.xml +``` + +if you are using LinkServer to flash your board, append your path with the following command: +``` +export PATH=$PATH:/usr/local/LinkServer_1.3.15/binaries/ +``` + +#### Note: +Use full path names in above environment variables, do not use special character `~` to represent your home directory. + +### Explore available options (works on Linux) +``` +make + +# will get you +clean # clean all projects +nxpvee-ui-clean # clean UI project +nxpvee-ui-gdb # debug UI project using gdb and jlink +nxpvee-ui-java_run # run simulation, you can override java main using MAIN=com.nxp.animatedMascot.AnimatedMascot make nxpvee-ui-java_run +nxpvee-ui-flash # flash board using jlink +nxpvee-ui-gdb_cmsisdap # debug UI project using gdb and CMSIS +nxpvee-ui.prj # build complete UI project +nxpvee-ui-flash_cmsisdap # flash board using CMSIS +nxpvee-ui-java_rebuild # rebuild java app +nxpvee-validation.prj # compile and run validation +``` + +### compile and flash +``` +make nxpvee-ui.prj + +# flash with a J-Link probe +make nxpvee-ui-flash + +# or flash with USB using CMSIS-DAP +make nxpvee-ui-flash_cmsisdap +``` + +### Compilation defaults +Demo app is compiled with +- NET +- SSL +by default + +### compile with just NET support enabled +``` +make nxpvee-ui.prj CMAKE_OPTS="-DENABLE_NET=1" +``` + + +### compile Ai demo +``` +make nxpvee-ui.prj CMAKE_OPTS="-DENABLE_AI=1" MAIN=com.nxp.aiSample.AiMain +``` + + +### debug +``` +make nxpvee-ui-gdb +# or +make nxpvee-ui-gdb_cmsisdap +``` + +### Ninja +to speed up compilation you can use ninja instead of make +``` +MAKE=ninja make nxpvee-ui.prj +``` + +### Compile Release image +to compile release image you can +``` +make nxpvee-ui.prj RELEASE=1 +``` + +### Compile using production license +to compile using a production license, a dongle is needed +``` +make nxpvee-ui.prj USAGE=prod +``` + + +### Compiling using west +It is possible to compile the whole Java app and the BSP using west + +``` +west build +``` + +#### To compile in verbose mode +``` +west build -- -DVERB=1 +``` + +#### To compile in production mode +``` +west build -- -DJUSAGE=prod +``` + +#### To compile the AI example + +``` + west build -- -DJMAIN=com.nxp.aiSample.AiMain -DENABLE_AI=1 +``` + + + +#### To compile the with net support +``` + west build -- -DENABLE_NET=1 +``` + +#### To flash using jlink +``` +west flash +``` + +#### To debug using jlink/gdb +``` +west debug +``` + + + + +## Tutorial: Using native C functions from the high level application +Some functions directly used by the high-level application can be implemented in C. It is called the [Native Interface Mechanism](https://docs.microej.com/en/latest/VEEPortingGuide/native.html). + +A native method is declared in the Application but is implemented in the native world. So a native declaration requires a C and Java implementation for the Simulator. You can find an example of a native method on [this page](https://docs.microej.com/en/latest/VEEPortingGuide/sni.html?highlight=native#example). + +You can have custom natives specific to the Java application (less portable between VEE Ports but fast execution). On the other hand, you can use native methods provided by [Foundation Libraries](https://docs.microej.com/en/latest/glossary.html#term-Foundation-Library) (Portable between VEE Ports but takes more time at the execution). + +The SimpleGFX application uses of C native function to calculate rectangles' coordinates (mainly for demonstration's sake). + +### Declaring and using native functions in the Java world +It is recommended to store all your native methods in the same public class. This public class contains methods with the same parameters as the C native functions. + +The name of the C function is `Java___`. Any underscore (`_`) character in `package_name`, `class_name`, or `function_name` is replaced by `_1`. Dots (`.`) are replaced by underscores `_`. + +For these reasons, it is handy to stick to Java naming conventions and use camel case for class and method names and lowercase only package names. + +For example: +```` +package com.nxp.application; + +public class MyClassNatives { + /* package */ native static int NativeFunction(int a); +}; +```` + +This can be used in the application source code this way: +```` +j = MyClassNatives.NativeFunction(i); +```` + +### Implementing the native functions in C world +The native functions are implemented in C, with a name deriving from the package name and the native class name. +In the previous example, we would have: +```` +int Java_com_nxp_application_MyClassNatives_NativeFunction(int a) +{ + int i; + +[...] + + return i; +} +```` + +When you implement a native method, it is recommended to use the type of `sni.h` rather than the native type. This ensures type consistency between Java and C. +You could use `jint` instead of `int` in the example above. + +The `sni.h` file is located on `nxp-vee-mcxn947-frdm/bsp/projects/microej/platform/inc` folder. + +### Implementing a mockup of the native functions for the simulator +Mockup functions are used to simulate the behavior of native functions when using the MicroEJ SDK Simulator. Mockups are detailed in the [MicroEJ website](https://docs.microej.com/en/latest/PlatformDeveloperGuide/mock.html). + +They are implementated in a different MicroEJ SDK project (`microej/mock`). + +The name of the file containing the mockup functions is supposed to be the same as the one where the native functions are declared in the application project (e.g. `SimpleGFXNatives.java`). + +The file may look like this: +```` +package com.nxp.application; + +public class MyClassNatives { + static int NativeFunction(int a) { + int i; + + [...] + + return i; + } +}; +```` + +Please note that this project mockup must be added as a dependency inside the VEE Port's `module.ivy` file. The `module.ivy` file is located in the `microej/vee-port-configuration` folder. You will find inside all the dependencies used by the VEE Port. + +![Mockup Declaration in platform](Documentation/pictures/MCXN947/sdk_mockup_declaration_in_platform.png) + +The `org` and `name` fields can be found inside the mockup's `module.ivy` file (respectively `organisation` and `module`): + +![Mockup org and name declaration](Documentation/pictures/common/sdk_mockup_org_name_declaration.png) + +After any modification to the mockup project, you need to rebuild the mock (right click on the mock project and select `Build Module`) and the platform (see [Build the platform](#build-the-vee-port)). + +## Get familiar with MICROEJ + +To discover insights about MicroEJ technology, please follow some of the entry points below. In addition, you will find useful links to our documentation and our GitHub. + +### Examples + +You can try to run other examples on our VEE Port. Here is an exhaustive list of them so that you can go further in the MicroEJ technology: + +* [Understand How to Build a Firmware](https://docs.microej.com/en/latest/Tutorials/tutorialUnderstandMicroEJFirmwareBuild.html): It is a document that describes the components, their dependencies, and the process involved in the build of a Firmware. +* [Get Started With GUI](https://docs.microej.com/en/latest/Tutorials/getStartedWithGUI/index.html): It is a guided tutorial to get the basics concepts of our UI. +* [Github resources](https://github.com/MicroEJ): + * How to use [foundation libraries](https://github.com/MicroEJ/Example-Standalone-Foundation-Libraries) on the Virtual Device or on board. + * Various examples of [how-to's](https://github.com/MicroEJ/How-To). + * Some [Demo projects](https://github.com/orgs/MicroEJ/repositories?q=demo&type=all&language=&sort=). + + +### MICROEJ Documentation + +You can take a look at the MICROEJ development documentation. +Below you can find some important chapters: +* [Application Developer Guide](https://docs.microej.com/en/latest/ApplicationDeveloperGuide/index.html): It covers concepts essential to MicroEJ Applications design. +* [MICROEJ VEE Port Developer Guide](https://docs.microej.com/en/latest/VEEPortingGuide/index.html): It covers the main process and configuration of a MicroEJ VEE. +* [Tutorials](https://docs.microej.com/en/latest/Tutorials/index.html#): There are multiple tutorials to master different subjects about the MicroEJ environment (including UI development, code quality and debug, CI/CD…). + +## Troubleshooting + +### License Error when building application + +#### [M65] - License check failed + +If you have the following error `[M65] - License check failed [tampered (3)]`, please follow the steps on this [page](https://forum.microej.com/t/license-check-fail-workaround-on-microej-sdk-with-jdk-version-8u351/1182) + + + diff --git a/SCR-nxpvee-mcxn947-frdm.txt b/SCR-nxpvee-mcxn947-frdm.txt new file mode 100644 index 0000000..7b624df --- /dev/null +++ b/SCR-nxpvee-mcxn947-frdm.txt @@ -0,0 +1,503 @@ +Release Name: NXPVEE-MCXN947-FRDM +Release Version: 1.0.0 +Date: April 2024 +Package License: LICENSE.txt +Outgoing License: LA_OPT_NXP_Software_License v54 February 2024 - Section 2.3 applies + +SDK_Peripheral_Driver Name: SDK Peripheral Driver + Version: 2.x.x + Outgoing License: BSD-3-Clause + License File: Licenses/COPYING-BSD-3 + Format: source code + Description: Peripheral drivers are designed for + the most common use cases identified for the + underlying hardware block. + Location: bsp/mcux-sdk/core/devices//drivers + Origin: NXP (BSD-3-Clause) + +SDK_Device Name: SDK SoC files + Version: NA + Outgoing License: BSD-3-Clause + License File: Licenses/COPYING-BSD-3 + Format: source code, linker files + Description: Device system files, template files, + IDE related startup and linker files. + Location: bsp/mcux-sdk/core/devices// + Origin: NXP (BSD-3-Clause) + +SDK_Components Name: SDK components and board peripheral drivers + Version: NA + Outgoing License: BSD-3-Clause + License File: Licenses/COPYING-BSD-3 + Format: source code + Description: SDK components and board peripheral + drivers, for example, flash and codec drivers. + Location: bsp/mcux-sdk/core/components/ + Origin: NXP (BSD-3-Clause), ITE (BSD-3-Clause) + +CMSIS Name: CMSIS + Version: 5.8.0 + Outgoing License: Apache License 2.0 + License File: bsp/mcux-sdk/core/CMSIS/LICENSE.txt + Format: source code + Description: Vendor-independent hardware + abstraction layer for microcontrollers that are + based on Arm Cortex processors, distributed by + ARM. cores + Location: bsp/mcux-sdk/core/CMSIS/ + Origin: ARM (Apache-2.0) - + https://github.com/ARM-software/CMSIS_5/releases/tag/5.8.0 + +cmsis_drivers Name: SDK CMSIS Peripheral Drivers + Version: 2.x.x + Outgoing License: Apache License 2.0 + License File: bsp/mcux-sdk/core/CMSIS/LICENSE.txt + Format: source code + Description: CMSIS Peripheral drivers are designed + to provide hardware independent APIs which make + application reusable across a wide range of + supported microcontroller devices. + Location: bsp/mcux-sdk/core/devices//cmsis_drivers + Origin: NXP (Apache License 2.0) + +eiq_tensorflow_lite Name: TensorFlow Lite for Microcontrollers + Version: 23-09-18 (commit dc64e48) + Outgoing License: Apache-2.0 + License File: Licenses/LICENSE-2.0.txt + Format: source code + Description: Software library for running machine + learning models on embedded devices + Location: bsp/mcux-sdk/middleware/eiq/tensorflow-lite + Origin: See middleware/eiq/tensorflow-lite/AUTHORS + Url: https://github.com/tensorflow/tensorflow + +eiq_FFT2D Name: FFT2D + Version: NA + Outgoing License: Public Domain + License File: bsp/mcux-sdk/middleware/eiq/tensorflow-lite/ + third_party/fft2d/LICENSE + Format: source code + Description: FFT package in C + Location: bsp/mcux-sdk/middleware/eiq/tensorflow-lite/ + third_party/fft2d + Origin: Takuya Ooura + Url: http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html + +eiq_FlatBuffers Name: FlatBuffers + Version: 2.0.6 (commit a66de58) + Outgoing License: Apache-2.0 + License File: Licenses/LICENSE-2.0.txt + Format: source code + Description: Cross platform serialization library + Location: + bsp/mcux-sdk/middleware/eiq/tensorflow-lite/third_party/flatbuffers + Origin: https://google.github.io/flatbuffers + Url: https://github.com/google/flatbuffers + +eiq_gemmlowp Name: gemmlowp + Version: NA (commit 719139c) + Outgoing License: Apache-2.0 + License File: Licenses/LICENSE-2.0.txt + Format: source code + Description: A small self-contained low-precision GEMM library + Location: + bsp/mcux-sdk/middleware/eiq/tensorflow-lite/third_party/gemmlowp + Origin: See + bsp/mcux-sdk/middleware/eiq/tensorflow-lite/third_party/ + gemmlowp/AUTHORS + Url: https://github.com/google/gemmlowp + +eiq_KissFFT Name: Kiss FFT + Version: 1.3.0 + Outgoing License: BSD-3-Clause + License File: Licenses/COPYING-BSD-3 + Format: source code + Description: A mixed-radix Fast Fourier Transform library + Location: + bsp/mcux-sdk/middleware/eiq/tensorflow-lite/third_party/kissfft + Origin: Mark Borgerding + Url: https://github.com/mborgerding/kissfft + +eiq_ruy Name: ruy + Version: NA (commit d371283) + Outgoing License: Apache-2.0 + License File: Licenses/LICENSE-2.0.txt + Format: source code + Description: The ruy matrix multiplication library + Location: + bsp/mcux-sdk/middleware/eiq/tensorflow-lite/third_party/ruy + Origin: Google, Inc. + Url: https://github.com/google/ruy + +eiq_tensorflow_lite_micro_cName: CMSIS-NN library +msis_nn Version: 23.08 (commit dc64e48) + Outgoing License: Apache-2.0 + License File: Licenses/LICENSE-2.0.txt + Format: source code + Description: A neural network kernels library for + Cortex-M cores from ARM + Location: + middleware/eiq/tensorflow-lite/third_party/cmsis_nn + Origin: ARM + Url: https://github.com/ARM-software/CMSIS-NN + +fatfs Name: FatFs + Version: 0.14b + Outgoing License: FatFs License + License File: bsp/mcux-sdk/middleware/fatfs/LICENSE.txt + Format: source code + Description: Generic FAT file system for small + embedded devices. + Location: bsp/mcux-sdk/middleware/fatfs + Origin: Electronic Lives Mfg. by ChaN of Ageo + city, Japan (FatFs License) + Approved open source license: Yes + Url: http://elm-chan.org/fsw/ff/00index_e.html + +freertos_kernel Name: FreeRTOS + Version: 10.5.1_rev0 + Outgoing License: MIT + License File: bsp/mcux-sdk/rtos/freertos/freertos-kernel/LICENSE.md + Format: source code + Description: Open source RTOS kernel for small + devices + Location: bsp/mcux-sdk/rtos/freertos/freertos-kernel + Origin: Amazon (MIT) + Url: https://aws.amazon.com/freertos/ + +lwip Name: lwIP TCP/IP Stack + Version: lwIP git repository (2023-01-03, branch: + master, SHA-1: + 3fe8d2fc43a9b69f7ed28c63d44a7744f9c0def9) + Outgoing License: BSD-3-Clause + License File: bsp/mcux-sdk/middleware/lwip/COPYING + Format: source code + Description: A light-weight TCP/IP stack + Location: bsp/mcux-sdk/middleware/lwip + Origin: NXP (BSD-3-Clause) Swedish Institute of + Computer Science (BSD-3-Clause) - + http://savannah.nongnu.org/projects/lwip + +mbedtls Name: Mbed TLS + Version: 2.28.5 + Outgoing License: Apache-2.0 + License File: Licenses/LICENSE-2.0.txt + Format: source code + Description: Cryptographic and SSL/TLS Library + Location: bsp/mcux-sdk/middleware/mbedtls + Origin: ARM (Apache-2.0) + https://github.com/Mbed-TLS/mbedtls/releases/tag/v2.28.5 + +sdmmc Name: SD MMC SDIO Card middleware + Version: 2.2.7 + Outgoing License: BSD-3-Clause + License File: Licenses/COPYING-BSD-3 + Format: source code + Description: A software component support SD card, + eMMC card, SDIO card. + Location: bsp/mcux-sdk/middleware/sdmmc + Origin: NXP (BSD-3-Clause) + +SimpleGFX Name: SimpleGFX + Version: 0.1 + Outgoing License: BSD-3-Clause + License File: microej/apps/LICENSE.txt + Format: source code + Description: example of a graphics VEE application + Location: microej/apps/src/main/java/com/nxp/simpleGFX + Origin: NXP (BSD-3-Clause) + +scripts Name: scripts + Version: 3.5.0 + Outgoing License: Apache License 2.0 + License File: Licenses/LICENSE-2.0.txt + Format: python scripts + Description: python scripts to compile and flash + a project using west meta-tool + Location: scripts/ + Origin: Zephyr (Apache-2.0) - + https://github.com/zephyrproject-rtos/zephyr/tree/zephyr-v3.5.0 + +MicroEJ BSP Name: MicroEJ BSP + Version: 1.x.x + Outgoing License: BSD-3-Clause + License File: Licenses/COPYING-BSD-3 + Format: source code + Description: Board support package for mcxn947 + Location: bsp/projects/microej (excluding subdirectories thirdparty, gpio and ai) + Origin: MicroEJ (https://www.microej.com/) + +MicroEJ ARCHITECTURE Name: Microej Architecture + Version: flopi4G25-8.1.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: MicroEJ Architecture for GNU Tools for ARM Embedded Processors 4.8. + Location: dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://repository.microej.com/architectures/com/microej/architecture/CM4/CM4hardfp_GCC48/flopi4G25/8.1.0/ + +MicroEJ BASICTOOL Name: Basic Tool + Version: 1.5.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Miscellaneous tools + Location: transitive dependency of apps/module.ivy + Origin: MicroEJ + Url: https://repository.microej.com/javadoc/microej_5.x/apis/ej/basictool/package-summary.html + +MicroEJ BON Name: Beyond Profile (BON) + Version: 1.4 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Control memory usage and start-up sequences + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/ApplicationDeveloperGuide/runtime.html?highlight=edc#beyond-profile-bon + +MicroEJ COLLECTIONS Name: Collections + Version: 1.3.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Static methods that operate on or return collections + Location: transitive dependency of apps/module.ivy + Origin: MicroEJ + Url: https://repository.microej.com/javadoc/microej_5.x/apis/index.html?java/util/Collections.html + +MicroEJ DEVICE Name: Device Pack + Version: 1.2 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: The Device Foundation Library provides access to the device information. + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/device.html + +MicroEJ Device Pack Name: Device Pack + Version: 1.1.1 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: The Device Foundation Library provides access to the device information. + Location: dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/device.html + +MicroEJ DRAWING Name: Drawing + Version: 1.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Contains shapes rendering and image with transformation rendering algorithms + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://repository.microej.com/javadoc/microej_5.x/apis/ej/drawing/package-summary.html + +MicroEJ EDC Name: Embedded Device Configuration (EDC) + Version: 1.3 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Implementation of the minimal standard runtime environment for + embedded devices + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/ApplicationDeveloperGuide/runtime.html?highlight=edc#embedded-device-configuration-edc + +MicroEJ FRAMEWORK Name: Frontpanel Framework Library + Version: 1.1.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Frontpanel framework creation library + Location: dependency of MIMXRT1170-fp/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/PlatformDeveloperGuide/frontpanel.html + +MicroEJ FRONTPANEL Name: Frontpanel + Version: 1.1.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Frontpanel creation library + Location: dependency of MIMXRT1170-fp/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/PlatformDeveloperGuide/frontpanel.html + +MicroEJ FS Name: File System + Version: 2.1 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: The FS Foundation Library defines a low-level File System framework for embedded devices. + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/fs.html + +MicroEJ FS Pack Name: File System Pack + Version: 6.0.4 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: The FS Foundation Library defines a low-level File System framework for embedded devices. + Location: dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/fs.html + +MicroEJ HILEngine Name: Hardware In the Loop interface + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Simulates Java-to-C calls. + Location: dependency of nxpvee-mimxrt1170-evk-mock/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/PlatformDeveloperGuide/simulation.html + +MicroEJ IMAGEGENERATOR Name: Image Generator + Version: 7.7.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Off-board tool in charge of generating image data + Location: dependency of MIMXRT1170-fp/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/PlatformDeveloperGuide/uiImageGenerator.html + +MicroEJ JUNIT Name: Junit + Version: 1.7.1 + Outgoing License: Eclipse Public License - v 1.0 + License File: https://spdx.org/licenses/EPL-1.0.html + Description: Unit test framework + Location: dependency of apps/module.ivy + Origin: JUNIT + Url: https://junit.org/ + +MicroEJ KF Name: Kernel Features (KF) + Version: 1.7 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Java implementation of the Multi-Sandbox features + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/appendix/javalibs/kf.html + +MicroEJ MicroUI Name: MicroUI + Version: 3.1 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: MicroUI API module. + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/ApplicationDeveloperGuide/UI/MicroUI/index.html + +MicroEJ MicroUI Pack Name: MicroUI Pack + Version: 13.7.2 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Enable the creation of user interface in Java + Location: dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/ui.html + +MicroEJ MWT Name: Micro Widget Toolkit + Version: 3.3.1 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Symplify the creation and use of graphical user interface widgets in Java + Location: dependency of apps/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/ApplicationDeveloperGuide/UI/MWT/index.html + +MicroEJ NET Name: Networking + Version: 1.1 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: The Net module defines a low-level network framework for embedded devices. + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/networkCoreEngine.html + +MicroEJ NET Pack Name: MicroEJ Pack NET + Version: 10.4.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: This pack contains the networking modules group: NET, SSL & Security. + Location: dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/networkCoreEngine.html + +MicroEJ ECOM Name: Embedded COMmunication Foundation Library + Version: 2.1 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: ECOM is a generic communication library with abstract communication stream support + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/ecom.html + + +MicroEJ PUMP Name: Pump + Version: 2.0.2 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Used by MicroUI to manage events + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + +MicroEJ RESOURCE MANAGER Name: Resource Manager + Version: 1.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Manage resources + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + +MicroEJ SECURITY Name: Security + Version: 1.4 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: The Java module related to permission management. + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + +MicroEJ SNI Name: Simple Native Interface (SNI) + Version: 1.4.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Allow to call native method from managed code + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/sni.html + Origin: MicroEJ + +MicroEJ SSL Name: Secure Sockets Layer (SSL) + Version: 2.2 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Allow to create and establish an encrypted connection between a server and a client. + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/VEEPortingGuide/ssl.html + +MicroEJ TRACE Name: Trace + Version: 1.1 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Record integer based events for debugging and monitoring purposes + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + Url: https://docs.microej.com/en/latest/ApplicationDeveloperGuide/trace.html + +MicroEJ WATCHDOG Name: Watchdog + Version: 1.0 + Outgoing License: MicroEJ SDK EULA + License File: Licenses/MICROEJ_SDK_EULA.txt + Description: Watchdog used by MicroUI + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: MicroEJ + +NXP GPIO Name: nxp-foundation-library-gpio + Version: 1.0 + Outgoing License: BSD-3-Clause + License File: Licenses/COPYING-BSD-3 + Description: GPIO faundation library + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: NXP + +NXP AI Name: nxp-foundation-library-ai + Version: 1.0 + Outgoing License: BSD-3-Clause + License File: Licenses/COPYING-BSD-3 + Description: AI foundation library + Location: transitive dependency of vee-port-configuration/module.ivy + Origin: NXP diff --git a/bsp/.project b/bsp/.project new file mode 100644 index 0000000..f28e16e --- /dev/null +++ b/bsp/.project @@ -0,0 +1,11 @@ + + + nxp-mcxn947-bsp + + + + + + + + diff --git a/bsp/nvee_version.txt b/bsp/nvee_version.txt new file mode 100644 index 0000000..3eefcb9 --- /dev/null +++ b/bsp/nvee_version.txt @@ -0,0 +1 @@ +1.0.0 diff --git a/bsp/projects/common/bsp/sdmmc/ffconf.h b/bsp/projects/common/bsp/sdmmc/ffconf.h new file mode 100644 index 0000000..32641b1 --- /dev/null +++ b/bsp/projects/common/bsp/sdmmc/ffconf.h @@ -0,0 +1,317 @@ +#ifndef _FFCONF_H_ +#define _FFCONF_H_ + +/*---------------------------------------------------------------------------/ +/ Configurations of FatFs Module +/---------------------------------------------------------------------------*/ + +#define FFCONF_DEF 80286 /* Revision ID */ +/*---------------------------------------------------------------------------/ +/ MSDK adaptation configuration +/---------------------------------------------------------------------------*/ +#define SD_DISK_ENABLE +/* Available options are: +/ RAM_DISK_ENABLE +/ USB_DISK_ENABLE +/ SD_DISK_ENABLE +/ MMC_DISK_ENABLE +/ SDSPI_DISK_ENABLE +/ NAND_DISK_ENABLE */ + +/*---------------------------------------------------------------------------/ +/ Function Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_READONLY 0 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + + +#define FF_FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: Basic functions are fully enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define FF_USE_FIND 0 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + + +#define FF_USE_MKFS 1 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + + +#define FF_USE_FASTSEEK 0 +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define FF_USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define FF_USE_CHMOD 1 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ + + +#define FF_USE_LABEL 0 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define FF_USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ + + +#define FF_USE_STRFUNC 0 +#define FF_PRINT_LLI 0 +#define FF_PRINT_FLOAT 0 +#define FF_STRF_ENCODE 0 +/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. +/ +/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 +/ makes f_printf() support floating point argument. These features want C99 or later. +/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character +/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE +/ to be read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define FF_CODE_PAGE 850 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect code page setting can cause a file open failure. +/ +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +/ 0 - Include all code pages above and configured by f_setcp() +*/ + + +#define FF_USE_LFN 3 +#define FF_MAX_LFN 255 +/* The FF_USE_LFN switches the support for LFN (long file name). +/ +/ 0: Disable LFN. FF_MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function +/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and +/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. +/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can +/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN +/ specification. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ + + +#define FF_LFN_UNICODE 0 +/* This option switches the character encoding on the API when LFN is enabled. +/ +/ 0: ANSI/OEM in current CP (TCHAR = char) +/ 1: Unicode in UTF-16 (TCHAR = WCHAR) +/ 2: Unicode in UTF-8 (TCHAR = char) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) +/ +/ Also behavior of string I/O functions will be affected by this option. +/ When LFN is not enabled, this option has no effect. */ + + +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +/* This set of options defines size of file name members in the FILINFO structure +/ which is used to read out directory items. These values should be suffcient for +/ the file names to read. The maximum possible length of the read file name depends +/ on character encoding. When LFN is not enabled, these options have no effect. */ + + +#define FF_FS_RPATH 2 +/* This option configures support for relative path. +/ +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +*/ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define FF_VOLUMES 5 +/* Number of volumes (logical drives) to be used. (1-10) */ + + +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drives. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table is needed as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +*/ + + +#define FF_MULTI_PARTITION 0 +/* This option switches support for multiple volumes on the physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When this function is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ function will be available. */ + + +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +/* This set of options configures the range of sector size to be supported. (512, +/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and +/ harddisk, but a larger value may be required for on-board flash memory and some +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured +/ for variable sector size mode and disk_ioctl() function needs to implement +/ GET_SECTOR_SIZE command. */ + + +#define FF_LBA64 0 +/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) +/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ + + +#define FF_MIN_GPT 0x10000000 +/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and +/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ + + +#define FF_USE_TRIM 0 +/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ + + +#define FF_FS_EXFAT 0 +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ + + +#define FF_FS_NORTC 1 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2024 +/* The option FF_FS_NORTC switches timestamp feature. If the system does not have +/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the +/ timestamp feature. Every object modified by FatFs will have a fixed timestamp +/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to read current time form real-time clock. FF_NORTC_MON, +/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. +/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ + + +#define FF_FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at the first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + +#define FF_FS_LOCK 2 +/* The option FF_FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + + +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +#if FF_FS_REENTRANT +#include "FreeRTOS.h" +#include "semphr.h" +#define FF_SYNC_t SemaphoreHandle_t +#endif +/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this featuer. +/ +/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give() +/ function, must be added to the project. Samples are available in ffsystem.c. +/ +/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick. +*/ + + + +/*--- End of configuration options ---*/ + +#endif /* _FFCONF_H_ */ diff --git a/bsp/projects/common/bsp/sdmmc/sdcard_helper.c b/bsp/projects/common/bsp/sdmmc/sdcard_helper.c new file mode 100644 index 0000000..af63007 --- /dev/null +++ b/bsp/projects/common/bsp/sdmmc/sdcard_helper.c @@ -0,0 +1,140 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "ffconf.h" + +#if defined DEMO_SDCARD +#include "ff.h" +#include "diskio.h" +#include "fsl_sd.h" +#include "sdmmc_config.h" +#include "fsl_debug_console.h" +/*! + * @brief wait card insert function. + */ + +#ifdef SD_ENABLED +extern sd_card_t g_sd; /* sd card descriptor */ + +/* static values for fatfs */ +AT_NONCACHEABLE_SECTION(FATFS g_fileSystem); /* File system object */ +AT_NONCACHEABLE_SECTION(FIL g_fileObject); /* File object */ +AT_NONCACHEABLE_SECTION(BYTE work[FF_MAX_SS]); +#endif + + +#define SDCARD_TASK_STACK_SIZE (512) + +/* SD card management */ +static SemaphoreHandle_t sdcardSem; +static volatile bool sdcardInserted; +static volatile bool sdcardInsertedPrev; +static FATFS fileSystem; + +static volatile bool card_ready = 0; + +bool SDCARD_isCardReady() +{ + return card_ready; +} + +bool SDCARD_waitCardReady() +{ + while (SDCARD_isCardReady() == 0) + { + vTaskDelay( pdMS_TO_TICKS( 1000 ) ); + } + return true; +} + +static void APP_SDCARD_DetectCallBack(bool isInserted, void *userData) +{ + sdcardInserted = isInserted; + xSemaphoreGiveFromISR(sdcardSem, NULL); +} + +bool SDCARD_inserted(void) +{ + return (sdcardInserted); +} + +void APP_SDCARD_Task(void *param) +{ + const TCHAR driverNumberBuffer[3U] = {SDDISK + '0', ':', '/'}; + FRESULT error; + + sdcardSem = xSemaphoreCreateBinary(); + + BOARD_SD_Config(&g_sd, APP_SDCARD_DetectCallBack, BOARD_SDMMC_SD_HOST_IRQ_PRIORITY, NULL); + + PRINTF("[APP_SDCARD_Task] start\r\n"); + + /* SD host init function */ + if (SD_HostInit(&g_sd) != kStatus_Success) + { + PRINTF("[APP_SDCARD_Task] SD host init failed.\r\n"); + vTaskSuspend(NULL); + } + + /* Small delay for SD card detection logic to process */ + vTaskDelay(100 / portTICK_PERIOD_MS); + + while (1) + { + /* Block waiting for SDcard detect interrupt */ + xSemaphoreTake(sdcardSem, portMAX_DELAY); + + if (sdcardInserted != sdcardInsertedPrev) + { + sdcardInsertedPrev = sdcardInserted; + + SD_SetCardPower(&g_sd, false); + + if (sdcardInserted) + { + /* power on the card */ + SD_SetCardPower(&g_sd, true); + if (f_mount(&fileSystem, driverNumberBuffer, 0U)) + { + PRINTF("[APP_SDCARD_Task] Mount volume failed.\r\n"); + continue; + } + +#if (FF_FS_RPATH >= 2U) + error = f_chdrive((char const *)&driverNumberBuffer[0U]); + if (error) + { + PRINTF("[APP_SDCARD_Task] Change drive failed.\r\n"); + continue; + } +#endif + + PRINTF("[APP_SDCARD_Task] SD card drive mounted\r\n"); + + xSemaphoreGive(sdcardSem); + card_ready = 1; + } + } + vTaskDelay(500 / portTICK_PERIOD_MS); + } +} + +void START_SDCARD_Task(void *param) +{ + PRINTF("START_SDCARD_Task\r\n"); + if (xTaskCreate(APP_SDCARD_Task, "SDCard Task", SDCARD_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 5, NULL) != + pdPASS) + { + PRINTF("ERROR initializing audio\r\n"); + PRINTF("Failed to create application task\r\n"); + while (1) + ; + } +} +#endif diff --git a/bsp/projects/common/bsp/sdmmc/sdcard_helper.h b/bsp/projects/common/bsp/sdmmc/sdcard_helper.h new file mode 100644 index 0000000..894dc5f --- /dev/null +++ b/bsp/projects/common/bsp/sdmmc/sdcard_helper.h @@ -0,0 +1,19 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SDCARD_HELPER_H +#define SDCARD_HELPER_H + +#ifdef __cplusplus +extern "C" { +#endif + void START_SDCARD_Task(void *param); + bool SDCARD_isCardReady(); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bsp/projects/common/bsp/sdmmc/sdmmc_config.c b/bsp/projects/common/bsp/sdmmc/sdmmc_config.c new file mode 100644 index 0000000..e8e134a --- /dev/null +++ b/bsp/projects/common/bsp/sdmmc/sdmmc_config.c @@ -0,0 +1,273 @@ +/* + * Copyright 2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "sdmmc_config.h" +#include "fsl_port.h" +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +void BOARD_SDCardPowerControl(bool enable); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*!brief sdmmc dma buffer */ +AT_NONCACHEABLE_SECTION_ALIGN(static uint32_t s_sdmmcHostDmaBuffer[BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE], + SDMMCHOST_DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE); +#if defined(SDIO_ENABLED) || defined(SD_ENABLED) +static sd_detect_card_t s_cd; +static sd_io_voltage_t s_ioVoltage = { + .type = BOARD_SDMMC_SD_IO_VOLTAGE_CONTROL_TYPE, + .func = NULL, +}; +#endif +static sdmmchost_t s_host; + +#ifdef SDIO_ENABLED +static sdio_card_int_t s_sdioInt; +#endif + +GPIO_HANDLE_DEFINE(s_CardDetectGpioHandle); +GPIO_HANDLE_DEFINE(s_PowerResetGpioHandle); + +/******************************************************************************* + * Code + ******************************************************************************/ +uint32_t BOARD_USDHC1ClockConfiguration(void) +{ + /* attach FRO HF to USDHC */ + CLOCK_SetClkDiv(kCLOCK_DivUSdhcClk, 1u); + CLOCK_AttachClk(kFRO_HF_to_USDHC); + + return CLOCK_GetUsdhcClkFreq(); +} + +#if defined(SDIO_ENABLED) || defined(SD_ENABLED) +bool BOARD_SDCardGetDetectStatus(void) +{ + uint8_t pinState; + + if (HAL_GpioGetInput(s_CardDetectGpioHandle, &pinState) == kStatus_HAL_GpioSuccess) + { + if (pinState == BOARD_SDMMC_SD_CD_INSERT_LEVEL) + { + return true; + } + } + + return false; +} + +void SDMMC_SD_CD_Callback(void *param) +{ + if (s_cd.callback != NULL) + { + s_cd.callback(BOARD_SDCardGetDetectStatus(), s_cd.userData); + } +} + +void BOARD_SDCardDAT3PullFunction(uint32_t status) +{ + if (status == kSD_DAT3PullDown) + { + const port_pin_config_t port2_6_pinK2_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as SDHC0_D3 */ + kPORT_MuxAlt3, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_6 (pin K2) is configured as SDHC0_D3 */ + PORT_SetPinConfig(PORT2, 6U, &port2_6_pinK2_config); + } + else + { + const port_pin_config_t port2_6_pinK2_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as SDHC0_D3 */ + kPORT_MuxAlt3, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_6 (pin K2) is configured as SDHC0_D3 */ + PORT_SetPinConfig(PORT2, 6U, &port2_6_pinK2_config); + } +} + +void BOARD_SDCardDetectInit(sd_cd_t cd, void *userData) +{ + uint8_t pinState; + + /* install card detect callback */ + s_cd.cdDebounce_ms = BOARD_SDMMC_SD_CARD_DETECT_DEBOUNCE_DELAY_MS; + s_cd.type = BOARD_SDMMC_SD_CD_TYPE; + s_cd.cardDetected = BOARD_SDCardGetDetectStatus; + s_cd.callback = cd; + s_cd.userData = userData; + + if (BOARD_SDMMC_SD_CD_TYPE == kSD_DetectCardByGpioCD) + { + hal_gpio_pin_config_t sw_config = { + kHAL_GpioDirectionIn, + 0, + BOARD_SDMMC_SD_CD_GPIO_PORT, + BOARD_SDMMC_SD_CD_GPIO_PIN, + }; + HAL_GpioInit(s_CardDetectGpioHandle, &sw_config); + HAL_GpioSetTriggerMode(s_CardDetectGpioHandle, BOARD_SDMMC_SD_CD_INTTERUPT_TYPE); + HAL_GpioInstallCallback(s_CardDetectGpioHandle, SDMMC_SD_CD_Callback, NULL); + + if (HAL_GpioGetInput(s_CardDetectGpioHandle, &pinState) == kStatus_HAL_GpioSuccess) + { + if (pinState == BOARD_SDMMC_SD_CD_INSERT_LEVEL) + { + if (cd != NULL) + { + cd(true, userData); + } + } + } + } + + /* register DAT3 pull function switch function pointer */ + if (BOARD_SDMMC_SD_CD_TYPE == kSD_DetectCardByHostDATA3) + { + s_cd.dat3PullFunc = BOARD_SDCardDAT3PullFunction; + BOARD_SDCardPowerControl(true); + } +} + +void BOARD_SDCardPowerResetInit(void) +{ + hal_gpio_pin_config_t sw_config = { + kHAL_GpioDirectionOut, + 1, + BOARD_SDMMC_SD_POWER_RESET_GPIO_PORT, + BOARD_SDMMC_SD_POWER_RESET_GPIO_PIN, + }; + HAL_GpioInit(s_PowerResetGpioHandle, &sw_config); +} + +void BOARD_SDCardPowerControl(bool enable) +{ + if (enable) + { + HAL_GpioSetOutput(s_PowerResetGpioHandle, 0); + } + else + { + HAL_GpioSetOutput(s_PowerResetGpioHandle, 1); + } +} +#endif + +#ifdef SD_ENABLED +void BOARD_SD_Config(void *card, sd_cd_t cd, uint32_t hostIRQPriority, void *userData) +{ + assert(card); + + s_host.dmaDesBuffer = s_sdmmcHostDmaBuffer; + s_host.dmaDesBufferWordsNum = BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE; + ((sd_card_t *)card)->host = &s_host; + ((sd_card_t *)card)->host->hostController.base = BOARD_SDMMC_SD_HOST_BASEADDR; + ((sd_card_t *)card)->host->hostController.sourceClock_Hz = BOARD_USDHC1ClockConfiguration(); + + ((sd_card_t *)card)->usrParam.cd = &s_cd; + ((sd_card_t *)card)->usrParam.pwr = BOARD_SDCardPowerControl; + ((sd_card_t *)card)->usrParam.ioStrength = NULL; + ((sd_card_t *)card)->usrParam.ioVoltage = &s_ioVoltage; + ((sd_card_t *)card)->usrParam.maxFreq = BOARD_SDMMC_SD_HOST_SUPPORT_SDR104_FREQ; + + BOARD_SDCardPowerResetInit(); + + BOARD_SDCardDetectInit(cd, userData); + + NVIC_SetPriority(BOARD_SDMMC_SD_HOST_IRQ, hostIRQPriority); +} +#endif + +#ifdef SDIO_ENABLED +void BOARD_SDIO_Config(void *card, sd_cd_t cd, uint32_t hostIRQPriority, sdio_int_t cardInt) +{ + assert(card); + + s_host.dmaDesBuffer = s_sdmmcHostDmaBuffer; + s_host.dmaDesBufferWordsNum = BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE; + ((sdio_card_t *)card)->host = &s_host; + ((sdio_card_t *)card)->host->hostController.base = BOARD_SDMMC_SDIO_HOST_BASEADDR; + ((sdio_card_t *)card)->host->hostController.sourceClock_Hz = BOARD_USDHC1ClockConfiguration(); + + ((sdio_card_t *)card)->usrParam.cd = &s_cd; + ((sdio_card_t *)card)->usrParam.pwr = BOARD_SDCardPowerControl; + ((sdio_card_t *)card)->usrParam.ioStrength = NULL; + ((sdio_card_t *)card)->usrParam.ioVoltage = &s_ioVoltage; + ((sdio_card_t *)card)->usrParam.maxFreq = BOARD_SDMMC_SD_HOST_SUPPORT_SDR104_FREQ; + if (cardInt != NULL) + { + s_sdioInt.cardInterrupt = cardInt; + ((sdio_card_t *)card)->usrParam.sdioInt = &s_sdioInt; + } + + BOARD_SDCardPowerResetInit(); + BOARD_SDCardDetectInit(cd, NULL); + + NVIC_SetPriority(BOARD_SDMMC_SDIO_HOST_IRQ, hostIRQPriority); +} +#endif + +#ifdef MMC_ENABLED +void BOARD_MMC_Config(void *card, uint32_t hostIRQPriority) +{ + assert(card); + + s_host.dmaDesBuffer = s_sdmmcHostDmaBuffer; + s_host.dmaDesBufferWordsNum = BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE; + ((mmc_card_t *)card)->host = &s_host; + ((mmc_card_t *)card)->host->hostController.base = BOARD_SDMMC_MMC_HOST_BASEADDR; + ((mmc_card_t *)card)->host->hostController.sourceClock_Hz = BOARD_USDHC1ClockConfiguration(); + ((mmc_card_t *)card)->host->tuningType = BOARD_SDMMC_MMC_TUNING_TYPE; + ((mmc_card_t *)card)->usrParam.ioStrength = NULL; + ((mmc_card_t *)card)->usrParam.maxFreq = BOARD_SDMMC_MMC_HOST_SUPPORT_HS200_FREQ; + + ((mmc_card_t *)card)->usrParam.capability |= BOARD_SDMMC_MMC_SUPPORT_8_BIT_DATA_WIDTH; + + ((mmc_card_t *)card)->hostVoltageWindowVCC = BOARD_SDMMC_MMC_VCC_SUPPLY; + ((mmc_card_t *)card)->hostVoltageWindowVCCQ = BOARD_SDMMC_MMC_VCCQ_SUPPLY; + + NVIC_SetPriority(BOARD_SDMMC_MMC_HOST_IRQ, hostIRQPriority); +} +#endif diff --git a/bsp/projects/common/bsp/sdmmc/sdmmc_config.h b/bsp/projects/common/bsp/sdmmc/sdmmc_config.h new file mode 100644 index 0000000..2f2cd5b --- /dev/null +++ b/bsp/projects/common/bsp/sdmmc/sdmmc_config.h @@ -0,0 +1,128 @@ +/* + * Copyright 2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _SDMMC_CONFIG_H_ +#define _SDMMC_CONFIG_H_ + +#include "fsl_common.h" + +#ifdef SD_ENABLED +#include "fsl_sd.h" +#endif +#ifdef MMC_ENABLED +#include "fsl_mmc.h" +#endif +#ifdef SDIO_ENABLED +#include "fsl_sdio.h" +#endif +#include "clock_config.h" +#include "fsl_adapter_gpio.h" +#include "fsl_sdmmc_host.h" +#include "fsl_sdmmc_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* @brief host basic configuration */ +#define BOARD_SDMMC_SD_HOST_BASEADDR USDHC0 +#define BOARD_SDMMC_SD_HOST_IRQ USDHC0_IRQn +#define BOARD_SDMMC_MMC_HOST_BASEADDR USDHC0 +#define BOARD_SDMMC_MMC_HOST_IRQ USDHC0_IRQn +#define BOARD_SDMMC_SDIO_HOST_BASEADDR USDHC0 +#define BOARD_SDMMC_SDIO_HOST_IRQ USDHC0_IRQn +/* @brief card detect configuration */ +#define BOARD_SDMMC_SD_CD_GPIO_BASE GPIO2 +#define BOARD_SDMMC_SD_CD_GPIO_PORT 2 +#define BOARD_SDMMC_SD_CD_GPIO_PIN 1U +#define BOARD_SDMMC_SD_CD_INTTERUPT_TYPE kHAL_GpioInterruptEitherEdge +#define BOARD_SDMMC_SD_CD_INSERT_LEVEL (0U) +/* @brief card detect type + * + * Note: if you want to use DAT3 as card detect pin, please make sure the DAT3 is pulled down with 100K resistor on + * board, it is not suggest to use the internal pull down function, from our test result, internal pull down is too + * strong to cover all the card. And please pay attention, DAT3 card detection cannot works during the card access, + * since the DAT3 will be used for data transfer, thus the functionality of card detect interrupt will be disabled as + * soon as card is detected. So If application would like to re-detect sdcard/sdiocard, please calling + * SD_PollingCardInsert/SDIO_PollingCardInsert The function will polling the card detect status and could yield CPU + * while RTOS and non-blocking adapter is using. + * DAT3 card detect maynot able to cover all the card(wifi/sdcard), as the difference of the card driver strength, + * application should pay attention of the limitation. + * + * Using card detect pin for card detection is recommended. + */ +#ifndef BOARD_SDMMC_SD_CD_TYPE +#define BOARD_SDMMC_SD_CD_TYPE kSD_DetectCardByGpioCD +#endif +#define BOARD_SDMMC_SD_CARD_DETECT_DEBOUNCE_DELAY_MS (100U) +/*! @brief SD power reset */ +#define BOARD_SDMMC_SD_POWER_RESET_GPIO_BASE GPIO0 +#define BOARD_SDMMC_SD_POWER_RESET_GPIO_PORT 0 +#define BOARD_SDMMC_SD_POWER_RESET_GPIO_PIN 11U +/*! @brief SD IO voltage */ +#define BOARD_SDMMC_SD_IO_VOLTAGE_CONTROL_TYPE kSD_IOVoltageCtrlNotSupport + +#define BOARD_SDMMC_SD_HOST_SUPPORT_SDR104_FREQ (200000000U) +#define BOARD_SDMMC_MMC_HOST_SUPPORT_HS200_FREQ (200000000U) +/*! @brief mmc configuration */ +#define BOARD_SDMMC_MMC_VCC_SUPPLY kMMC_VoltageWindows270to360 +#define BOARD_SDMMC_MMC_VCCQ_SUPPLY kMMC_VoltageWindows270to360 +/*! @brief align with cache line size */ +#define BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE (32U) +#define BOARD_SDMMC_MMC_SUPPORT_8_BIT_DATA_WIDTH 1U +#define BOARD_SDMMC_MMC_TUNING_TYPE 0 +/*!@ brief host interrupt priority*/ +#define BOARD_SDMMC_SD_HOST_IRQ_PRIORITY (5U) +#define BOARD_SDMMC_MMC_HOST_IRQ_PRIORITY (5U) +#define BOARD_SDMMC_SDIO_HOST_IRQ_PRIORITY (5U) +/*!@brief dma descriptor buffer size */ +#define BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE (32U) +/*! @brief cache maintain function enabled for RW buffer */ +#define BOARD_SDMMC_HOST_CACHE_CONTROL kSDMMCHOST_CacheControlRWBuffer + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +/******************************************************************************* + * API + ******************************************************************************/ +/*! + * @brief BOARD SD configurations. + * @param card card descriptor + * @param cd card detect callback + * @param userData user data for callback + */ +#ifdef SD_ENABLED +void BOARD_SD_Config(void *card, sd_cd_t cd, uint32_t hostIRQPriority, void *userData); +#endif + +/*! + * @brief BOARD SDIO configurations. + * @param card card descriptor + * @param cd card detect callback + * @param cardInt card interrupt + */ +#ifdef SDIO_ENABLED +void BOARD_SDIO_Config(void *card, sd_cd_t cd, uint32_t hostIRQPriority, sdio_int_t cardInt); +#endif + +/*! + * @brief BOARD MMC configurations. + * @param card card descriptor + * @param cd card detect callback + * @param userData user data for callback + */ +#ifdef MMC_ENABLED +void BOARD_MMC_Config(void *card, uint32_t hostIRQPriority); + +#endif + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* _BOARD_H_ */ diff --git a/bsp/projects/common/bsp/sdmmc/utility_sdmmc.cmake b/bsp/projects/common/bsp/sdmmc/utility_sdmmc.cmake new file mode 100644 index 0000000..4a0e3bc --- /dev/null +++ b/bsp/projects/common/bsp/sdmmc/utility_sdmmc.cmake @@ -0,0 +1,14 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: BSD-3-Clause + +include_guard() +message("sdmmc component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + "${CMAKE_CURRENT_LIST_DIR}/sdcard_helper.c" + "${CMAKE_CURRENT_LIST_DIR}/sdmmc_config.c" +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/. +) diff --git a/bsp/projects/common/scripts/build_mcu.sh b/bsp/projects/common/scripts/build_mcu.sh new file mode 100755 index 0000000..b3f9cb3 --- /dev/null +++ b/bsp/projects/common/scripts/build_mcu.sh @@ -0,0 +1,27 @@ +#/bin/bash + +WORKSPACE= +IDE= +PROJECT=rt1170_nxpvee + +help() { + echo "${0}: compile mcuxpressoide projecto from commandline" + echo " -w WORKSPACE" + echo " -i IDE" + echo " -p PROJECT (default ${PROJECT})" + exit 0 +} + +while getopts w:i:p:h FLAG +do + case "${FLAG}" in + w) WORKSPACE=${OPTARG};; + i) IDE=${OPTARG};; + p) PROJECT=${OPTARG};; + h) help;; + esac +done + +set -ue + +"${IDE}" -nosplash --launcher.suppressErrors -application org.eclipse.cdt.managedbuilder.core.headlessbuild -data "${WORKSPACE}" -build "${PROJECT}"/Release diff --git a/bsp/projects/common/scripts/s2s.bat b/bsp/projects/common/scripts/s2s.bat new file mode 100644 index 0000000..1b5b5cb --- /dev/null +++ b/bsp/projects/common/scripts/s2s.bat @@ -0,0 +1,15 @@ +@echo off +set S2S_TTY=%1 +set S2S_PORT=%2 + +netstat -an | findstr /RC:":%S2S_PORT% .*LISTENING" +if /I %errorlevel% NEQ 0 ( + cd microej/MCXN947-frdm_platform-CM4hardfp_GCC48-1.0.0/source + start "s2s.bat" cmd /k java ^ + -Djava.library.path="resources/os/Windows64" ^ + -cp "tools/*" ^ + com.is2t.serialsockettransmitter.SerialToSocketTransmitterBatch ^ + -port "%S2S_TTY%" ^ + -baudrate 115200 -databits 8 -parity none -stopbits 1 ^ + -hostPort "%S2S_PORT%" +) diff --git a/bsp/projects/common/scripts/s2s.sh b/bsp/projects/common/scripts/s2s.sh new file mode 100755 index 0000000..9fdacc7 --- /dev/null +++ b/bsp/projects/common/scripts/s2s.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -e +set -x + +S2S_TTY=${1} +S2S_PORT=${2} + +if [ "$(ss -a | grep "\<${S2S_PORT}\>")" == "" ] +then + cd microej/MCXN947-frdm_platform-CM4hardfp_GCC48-1.0.0/source + java \ + -Djava.library.path="resources/os/Linux64" \ + -cp "tools/*" \ + com.is2t.serialsockettransmitter.SerialToSocketTransmitterBatch \ + -port "${S2S_TTY}" \ + -baudrate 115200 -databits 8 -parity none -stopbits 1 \ + -hostPort "${S2S_PORT}" +fi diff --git a/bsp/projects/common/sdk_makefile/Makefile b/bsp/projects/common/sdk_makefile/Makefile new file mode 100644 index 0000000..23271ff --- /dev/null +++ b/bsp/projects/common/sdk_makefile/Makefile @@ -0,0 +1,102 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# + +COMMON_PATH=../../common/sdk_makefile + +define del_file + $(if $(filter $(OS),Windows_NT),$(if $(wildcard $(1)),cmd /c DEL /f /q $(subst /,\\,$(1)),),rm -f $(1)) +endef + +define del_dir + $(if $(filter $(OS),Windows_NT),$(if $(wildcard $(1)),cmd /c RD /s /q $(subst /,\\,$(1)),),rm -fr $(1)) +endef + +ifeq ($(OS),Windows_NT) +JLINKEXE="$(JLINK_INSTALLATION_DIR)/Jlink.exe" +JLINK_GDB="$(COMMON_PATH)/debug/jlink_gdb.bat" +else +JLINKEXE=JLinkExe +JLINK_GDB="$(COMMON_PATH)"/debug/jlink_gdb.sh +endif + +JLINK_SCRIPT="jlink_flash.script" + +MAKE ?= make +OBJCOPY="$(ARMGCC_DIR)/bin/arm-none-eabi-objcopy" + + +ifeq ($(OS),Windows_NT) +GDB="$(ARMGCC_DIR)/bin/arm-none-eabi-gdb.exe" +NUM_PROC= +CLEAN_SCRIPT="./clean.bat" +else +GDB=gdb-multiarch +NUM_PROC=$(shell nproc) +CLEAN_SCRIPT="./clean.sh" +endif + +ifeq ($(MAKE),make) +MAKE_OP=-j$(NUM_PROC) +endif + +BUILD_DIR=../armgcc/$(FLAVOUR) + +all: ../armgcc/$(FLAVOUR) remake + +ifeq ($(OS),Windows_NT) +BUILD_SCRIPT="./build_$(FLAVOUR).bat" +CMSIS_GDB_TEMP_FOLDER="$(TEMP)"/gdb.cmd +PROBE= +else +BUILD_SCRIPT=./build_$(FLAVOUR).sh +CMSIS_GDB_TEMP_FOLDER=/tmp/gdb.cmd +PROBE=--probeserial $(shell echo probelist | redlinkserv --commandline | grep 'Serial Number' | cut -d\= -f2) +endif + +../armgcc/$(FLAVOUR): + cd ../armgcc/ && $(BUILD_SCRIPT) $(MAKE) $(CMAKE_OPTS) + +remake: + $(MAKE) $(MAKE_OP) -C ../armgcc/ + $(OBJCOPY) -Obinary "$(BUILD_DIR)/$(TARGET).elf" "$(BUILD_DIR)/$(TARGET).bin" + $(OBJCOPY) -Oihex "$(BUILD_DIR)/$(TARGET).elf" "$(BUILD_DIR)/$(TARGET).hex" + +clean: +ifneq ("$(wildcard $(../armgcc/Makefile))","") + $(MAKE) -C ../armgcc/ clean +endif + $(call del_dir,$(BUILD_DIR)) + +distclean: + cd ../armgcc/ && $(CLEAN_SCRIPT) + +flash: ../armgcc/$(FLAVOUR) remake + $(call del_file,$(JLINK_SCRIPT)) + echo r > $(JLINK_SCRIPT) + echo loadbin "$(BUILD_DIR)/$(TARGET).bin" $(ADDRESS) >> $(JLINK_SCRIPT) + echo r >> $(JLINK_SCRIPT) + echo g >> $(JLINK_SCRIPT) + echo qc >> $(JLINK_SCRIPT) + $(JLINKEXE) -NoGui 1 -device $(DEVICE) -If SWD -Speed 10000 -CommanderScript $(JLINK_SCRIPT) + $(call del_file,$(JLINK_SCRIPT)) + +flash_cmsisdap: ../armgcc/$(FLAVOUR) remake + crt_emu_cm_redlink --flash-load-exec $(BUILD_DIR)/$(TARGET).elf \ + -p MCXN947 --bootromstall 0x50000040 $(PROBE) \ + -x $(COMMON_PATH)/cmsisdap_support \ + -CoreIndex=0 --flash-driver= \ + --PreconnectScript LS_preconnect_MCXN9XX.scp \ + --flash-hashing + +gdb_cmsisdap: ../armgcc/$(FLAVOUR) remake + sed "s+FILE_VALUE+$(BUILD_DIR)/$(TARGET).elf+;s+PROBESERIAL+$(PROBE)+" $(COMMON_PATH)/cmsisdap_support/gdb.commands > $(CMSIS_GDB_TEMP_FOLDER) + $(GDB) --command=$(CMSIS_GDB_TEMP_FOLDER) + +gdb: ../armgcc/$(FLAVOUR) remake + $(JLINK_GDB) $(DEVICE) + $(GDB) --command=$(COMMON_PATH)/debug/jlink.gdb $(BUILD_DIR)/$(TARGET).elf + +.PHONY : all remake clean dist_clean gdb diff --git a/bsp/projects/common/sdk_makefile/cmsisdap_support/MCXN947.xml b/bsp/projects/common/sdk_makefile/cmsisdap_support/MCXN947.xml new file mode 100644 index 0000000..1d75990 --- /dev/null +++ b/bsp/projects/common/sdk_makefile/cmsisdap_support/MCXN947.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/bsp/projects/common/sdk_makefile/cmsisdap_support/MCXN947_part.xml b/bsp/projects/common/sdk_makefile/cmsisdap_support/MCXN947_part.xml new file mode 100644 index 0000000..e3d3c56 --- /dev/null +++ b/bsp/projects/common/sdk_makefile/cmsisdap_support/MCXN947_part.xml @@ -0,0 +1,2 @@ + + MCXN947 MCXN9XX NXP Cortex-M33 Cortex-M Cortex-M33 (No DSP) Cortex-M diff --git a/bsp/projects/common/sdk_makefile/cmsisdap_support/crt_infolist.dtd b/bsp/projects/common/sdk_makefile/cmsisdap_support/crt_infolist.dtd new file mode 100644 index 0000000..396f962 --- /dev/null +++ b/bsp/projects/common/sdk_makefile/cmsisdap_support/crt_infolist.dtd @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bsp/projects/common/sdk_makefile/cmsisdap_support/gdb.commands b/bsp/projects/common/sdk_makefile/cmsisdap_support/gdb.commands new file mode 100644 index 0000000..344ff58 --- /dev/null +++ b/bsp/projects/common/sdk_makefile/cmsisdap_support/gdb.commands @@ -0,0 +1,32 @@ +set pagination off +set mi-async +set remotetimeout 60000 +set confirm off + +target extended-remote | crt_emu_cm_redlink -g \ +-mi -2 \ +-p MCXN947 \ +-vendor NXP \ +--bootromstall 0x50000040 \ +--PreconnectScript LS_preconnect_MCXN9XX.scp \ +--reset= \ +PROBESERIAL \ +-cache=disable \ +--flash-hashing \ +--flash-driver= \ +-x ../../common/sdk_makefile/cmsisdap_support \ +--no-packed \ +--err=redlink.err \ +--log=redlink.log + +set mem inaccessible-by-default off +mon ondisconnect cont +set arm force-mode thumb +mon capabilities +set remote hardware-breakpoint-limit 4 +file FILE_VALUE + +load + +b main +run diff --git a/bsp/projects/common/sdk_makefile/debug/jlink.gdb b/bsp/projects/common/sdk_makefile/debug/jlink.gdb new file mode 100644 index 0000000..e87af41 --- /dev/null +++ b/bsp/projects/common/sdk_makefile/debug/jlink.gdb @@ -0,0 +1,15 @@ +target extended-remote :2331 + +set print asm-demangle on +set backtrace limit 32 +break DefaultHandler +break HardFault +break main +monitor reset 2 + +load + +set language c +set $sp = *0x0 +# start the process but immediately halt the processor +stepi diff --git a/bsp/projects/common/sdk_makefile/debug/jlink_gdb.bat b/bsp/projects/common/sdk_makefile/debug/jlink_gdb.bat new file mode 100755 index 0000000..8fe1c90 --- /dev/null +++ b/bsp/projects/common/sdk_makefile/debug/jlink_gdb.bat @@ -0,0 +1,4 @@ +tasklist /nh /fi "imagename eq JLinkGDBServerCL.exe" | find /i "JLinkGDBServerCL.exe" +if errorlevel 1 ( + Start "" "%JLINK_INSTALLATION_DIR%/JLinkGDBServerCL.exe" -device "%~1" -if swd -ir +) diff --git a/bsp/projects/common/sdk_makefile/debug/jlink_gdb.sh b/bsp/projects/common/sdk_makefile/debug/jlink_gdb.sh new file mode 100755 index 0000000..564bd28 --- /dev/null +++ b/bsp/projects/common/sdk_makefile/debug/jlink_gdb.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# +# Copyright 2022 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# + +JLINKK_PID=$(pgrep JLinkGDBServer) +if [ "${JLINKK_PID}" == "" ] +then + JLinkGDBServer -device "${1}" -if swd -ir > /dev/null 2>&1 & +fi diff --git a/bsp/projects/common/segger/Config/Cortex-M/SEGGER_SYSVIEW_Config_FreeRTOS.c b/bsp/projects/common/segger/Config/Cortex-M/SEGGER_SYSVIEW_Config_FreeRTOS.c new file mode 100644 index 0000000..426ff24 --- /dev/null +++ b/bsp/projects/common/segger/Config/Cortex-M/SEGGER_SYSVIEW_Config_FreeRTOS.c @@ -0,0 +1,106 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +-------------------------- END-OF-HEADER ----------------------------- + +File : SEGGER_SYSVIEW_Config_FreeRTOS.c +Purpose : Sample setup configuration of SystemView with FreeRTOS. +Revision: $Rev: 7745 $ +*/ +#include "FreeRTOS.h" +#include "SEGGER_SYSVIEW.h" +#include "fsl_debug_console.h" + +extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI; + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ +// The application name to be displayed in SystemViewer +#define SYSVIEW_APP_NAME "FreeRTOS Demo Application" + +// The target device name +#define SYSVIEW_DEVICE_NAME "Cortex-M4" + +// Frequency of the timestamp. Must match SEGGER_SYSVIEW_GET_TIMESTAMP in SEGGER_SYSVIEW_Conf.h +#define SYSVIEW_TIMESTAMP_FREQ (configCPU_CLOCK_HZ) + +// System Frequency. SystemcoreClock is used in most CMSIS compatible projects. +#define SYSVIEW_CPU_FREQ configCPU_CLOCK_HZ + +// The lowest RAM address used for IDs (pointers) +#define SYSVIEW_RAM_BASE (0x10000000) + +/********************************************************************* +* +* _cbSendSystemDesc() +* +* Function description +* Sends SystemView description strings. +*/ +static void _cbSendSystemDesc(void) { + SEGGER_SYSVIEW_SendSysDesc("N="SYSVIEW_APP_NAME",D="SYSVIEW_DEVICE_NAME",O=FreeRTOS"); + SEGGER_SYSVIEW_SendSysDesc("I#15=SysTick"); +} +/********************************************************************* +* +* Global functions +* +********************************************************************** +*/ +void SEGGER_SYSVIEW_Conf(void) { + SEGGER_SYSVIEW_Init(SYSVIEW_TIMESTAMP_FREQ, SYSVIEW_CPU_FREQ, + &SYSVIEW_X_OS_TraceAPI, _cbSendSystemDesc); + SEGGER_SYSVIEW_SetRAMBase(SYSVIEW_RAM_BASE); + extern void* _SEGGER_RTT; + PRINTF("SEGGER_RTT block address: 0x%x\r\n", &(_SEGGER_RTT)); +} + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/Config/Global.h b/bsp/projects/common/segger/Config/Global.h new file mode 100644 index 0000000..08972f6 --- /dev/null +++ b/bsp/projects/common/segger/Config/Global.h @@ -0,0 +1,113 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------------------------------------------------- +File : Global.h +Purpose : Global types + In case your application already has a Global.h, you should + merge the files. In order to use Segger code, the types + U8, U16, U32, I8, I16, I32 need to be defined in Global.h; + additional definitions do not hurt. +Revision: $Rev: 12501 $ +---------------------------END-OF-HEADER------------------------------ +*/ + +#ifndef GLOBAL_H // Guard against multiple inclusion +#define GLOBAL_H + +#define U8 unsigned char +#define I8 signed char +#define U16 unsigned short +#define I16 signed short +#ifdef __x86_64__ +#define U32 unsigned +#define I32 int +#else +#define U32 unsigned long +#define I32 signed long +#endif + +// +// CC_NO_LONG_SUPPORT can be defined to compile test +// without long support for compilers that do not +// support C99 and its long type. +// +#ifdef CC_NO_LONG_SUPPORT + #define PTR_ADDR U32 +#else // Supports long type. +#if defined(_WIN32) && !defined(__clang__) && !defined(__MINGW32__) + // + // Microsoft VC6 compiler related + // + #define U64 unsigned __int64 + #define U128 unsigned __int128 + #define I64 __int64 + #define I128 __int128 + #if _MSC_VER <= 1200 + #define U64_C(x) x##UI64 + #else + #define U64_C(x) x##ULL + #endif +#else + // + // C99 compliant compiler + // + #define U64 unsigned long long + #define I64 signed long long + #define U64_C(x) x##ULL +#endif + +#if (defined(_WIN64) || defined(__LP64__)) // 64-bit symbols used by Visual Studio and GCC, maybe others as well. + #define PTR_ADDR U64 +#else + #define PTR_ADDR U32 +#endif +#endif // Supports long type. + +#endif // Avoid multiple inclusion + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/Config/SEGGER_RTT_Conf.h b/bsp/projects/common/segger/Config/SEGGER_RTT_Conf.h new file mode 100644 index 0000000..fbb83ba --- /dev/null +++ b/bsp/projects/common/segger/Config/SEGGER_RTT_Conf.h @@ -0,0 +1,428 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT_Conf.h +Purpose : Implementation of SEGGER real-time transfer (RTT) which + allows real-time communication on targets which support + debugger memory accesses while the CPU is running. +Revision: $Rev: 24316 $ + +*/ + +#ifndef SEGGER_RTT_CONF_H +#define SEGGER_RTT_CONF_H + +#ifdef __IAR_SYSTEMS_ICC__ + #include +#endif + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ + +// +// Take in and set to correct values for Cortex-A systems with CPU cache +// +//#define SEGGER_RTT_CPU_CACHE_LINE_SIZE (32) // Largest cache line size (in bytes) in the current system +//#define SEGGER_RTT_UNCACHED_OFF (0xFB000000) // Address alias where RTT CB and buffers can be accessed uncached +// +// Most common case: +// Up-channel 0: RTT +// Up-channel 1: SystemView +// +#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS + #define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) // Max. number of up-buffers (T->H) available on this target (Default: 3) +#endif +// +// Most common case: +// Down-channel 0: RTT +// Down-channel 1: SystemView +// +#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS + #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) // Max. number of down-buffers (H->T) available on this target (Default: 3) +#endif + +#ifndef BUFFER_SIZE_UP + #define BUFFER_SIZE_UP (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k) +#endif + +#ifndef BUFFER_SIZE_DOWN + #define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16) +#endif + +#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE + #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64) +#endif + +#ifndef SEGGER_RTT_MODE_DEFAULT + #define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0) +#endif + +/********************************************************************* +* +* RTT memcpy configuration +* +* memcpy() is good for large amounts of data, +* but the overhead is big for small amounts, which are usually stored via RTT. +* With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead. +* +* SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions. +* This is may be required with memory access restrictions, +* such as on Cortex-A devices with MMU. +*/ +#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP + #define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop +#endif +// +// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A targets +// +//#if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined (__ARM_ARCH_7A__)) +// #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) SEGGER_memcpy((pDest), (pSrc), (NumBytes)) +//#endif + +// +// Target is not allowed to perform other RTT operations while string still has not been stored completely. +// Otherwise we would probably end up with a mixed string in the buffer. +// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here. +// +// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4. +// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches. +// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly. +// (Higher priority = lower priority number) +// Default value for embOS: 128u +// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC +// or define SEGGER_RTT_LOCK() to completely disable interrupts. +// +#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20) +#endif + +/********************************************************************* +* +* RTT lock configuration for SEGGER Embedded Studio, +* Rowley CrossStudio and GCC +*/ +#if ((defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM) && !defined(WIN32)) + #if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs %0, primask \n\t" \ + "movs r1, #1 \n\t" \ + "msr primask, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : \ + ); \ + } + #elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs %0, basepri \n\t" \ + "mov r1, %1 \n\t" \ + "msr basepri, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : \ + ); \ + } + + #elif (defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs r1, CPSR \n\t" \ + "mov %0, r1 \n\t" \ + "orr r1, r1, #0xC0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \ + "mrs r1, CPSR \n\t" \ + "bic r1, r1, #0xC0 \n\t" \ + "and r0, r0, #0xC0 \n\t" \ + "orr r1, r1, r0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : "r0", "r1", "cc" \ + ); \ + } + #elif defined(__riscv) || defined(__riscv_xlen) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("csrr %0, mstatus \n\t" \ + "csrci mstatus, 8 \n\t" \ + "andi %0, %0, 8 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("csrr a1, mstatus \n\t" \ + "or %0, %0, a1 \n\t" \ + "csrs mstatus, %0 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : "a1" \ + ); \ + } + #else + #define SEGGER_RTT_LOCK() + #define SEGGER_RTT_UNLOCK() + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for IAR EWARM +*/ +#ifdef __ICCARM__ + #if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) || \ + (defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_PRIMASK(); \ + __set_PRIMASK(1); + + #define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \ + } + #elif (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || \ + (defined (__ARM7M__) && (__CORE__ == __ARM7M__)) || \ + (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) || \ + (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_BASEPRI(); \ + __set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); + + #define SEGGER_RTT_UNLOCK() __set_BASEPRI(_SEGGER_RTT__LockState); \ + } + #elif (defined (__ARM7A__) && (__CORE__ == __ARM7A__)) || \ + (defined (__ARM7R__) && (__CORE__ == __ARM7R__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs r1, CPSR \n\t" \ + "mov %0, r1 \n\t" \ + "orr r1, r1, #0xC0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \ + "mrs r1, CPSR \n\t" \ + "bic r1, r1, #0xC0 \n\t" \ + "and r0, r0, #0xC0 \n\t" \ + "orr r1, r1, r0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : "r0", "r1", "cc" \ + ); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for IAR RX +*/ +#ifdef __ICCRX__ + #define SEGGER_RTT_LOCK() { \ + unsigned long _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_interrupt_state(); \ + __disable_interrupt(); + + #define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \ + } +#endif + +/********************************************************************* +* +* RTT lock configuration for IAR RL78 +*/ +#ifdef __ICCRL78__ + #define SEGGER_RTT_LOCK() { \ + __istate_t _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_interrupt_state(); \ + __disable_interrupt(); + + #define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \ + } +#endif + +/********************************************************************* +* +* RTT lock configuration for KEIL ARM +*/ +#ifdef __CC_ARM + #if (defined __TARGET_ARCH_6S_M) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + register unsigned char _SEGGER_RTT__PRIMASK __asm( "primask"); \ + _SEGGER_RTT__LockState = _SEGGER_RTT__PRIMASK; \ + _SEGGER_RTT__PRIMASK = 1u; \ + __schedule_barrier(); + + #define SEGGER_RTT_UNLOCK() _SEGGER_RTT__PRIMASK = _SEGGER_RTT__LockState; \ + __schedule_barrier(); \ + } + #elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + register unsigned char BASEPRI __asm( "basepri"); \ + _SEGGER_RTT__LockState = BASEPRI; \ + BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \ + __schedule_barrier(); + + #define SEGGER_RTT_UNLOCK() BASEPRI = _SEGGER_RTT__LockState; \ + __schedule_barrier(); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for TI ARM +*/ +#ifdef __TI_ARM__ + #if defined (__TI_ARM_V6M0__) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_PRIMASK(); \ + __set_PRIMASK(1); + + #define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \ + } + #elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); + + #define SEGGER_RTT_UNLOCK() _set_interrupt_priority(_SEGGER_RTT__LockState); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for CCRX +*/ +#ifdef __RX + #include + #define SEGGER_RTT_LOCK() { \ + unsigned long _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = get_psw() & 0x010000; \ + clrpsw_i(); + + #define SEGGER_RTT_UNLOCK() set_psw(get_psw() | _SEGGER_RTT__LockState); \ + } +#endif + +/********************************************************************* +* +* RTT lock configuration for embOS Simulation on Windows +* (Can also be used for generic RTT locking with embOS) +*/ +#if defined(WIN32) || defined(SEGGER_RTT_LOCK_EMBOS) + +void OS_SIM_EnterCriticalSection(void); +void OS_SIM_LeaveCriticalSection(void); + +#define SEGGER_RTT_LOCK() { \ + OS_SIM_EnterCriticalSection(); + +#define SEGGER_RTT_UNLOCK() OS_SIM_LeaveCriticalSection(); \ + } +#endif + +/********************************************************************* +* +* RTT lock configuration fallback +*/ +#ifndef SEGGER_RTT_LOCK + #define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts) +#endif + +#ifndef SEGGER_RTT_UNLOCK + #define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state) +#endif + +#endif +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/Config/SEGGER_SYSVIEW_Conf.h b/bsp/projects/common/segger/Config/SEGGER_SYSVIEW_Conf.h new file mode 100644 index 0000000..e372e28 --- /dev/null +++ b/bsp/projects/common/segger/Config/SEGGER_SYSVIEW_Conf.h @@ -0,0 +1,85 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +-------------------------- END-OF-HEADER ----------------------------- + +File : SEGGER_SYSVIEW_Conf.h +Purpose : SEGGER SystemView configuration file. + Set defines which deviate from the defaults (see SEGGER_SYSVIEW_ConfDefaults.h) here. +Revision: $Rev: 21292 $ + +Additional information: + Required defines which must be set are: + SEGGER_SYSVIEW_GET_TIMESTAMP + SEGGER_SYSVIEW_GET_INTERRUPT_ID + For known compilers and cores, these might be set to good defaults + in SEGGER_SYSVIEW_ConfDefaults.h. + + SystemView needs a (nestable) locking mechanism. + If not defined, the RTT locking mechanism is used, + which then needs to be properly configured. +*/ + +#ifndef SEGGER_SYSVIEW_CONF_H +#define SEGGER_SYSVIEW_CONF_H + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ + +/********************************************************************* +* TODO: Add your defines here. * +********************************************************************** +*/ + + +#endif // SEGGER_SYSVIEW_CONF_H + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER.h b/bsp/projects/common/segger/SEGGER.h new file mode 100644 index 0000000..0b1703c --- /dev/null +++ b/bsp/projects/common/segger/SEGGER.h @@ -0,0 +1,248 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------------------------------------------------- +File : SEGGER.h +Purpose : Global types etc & general purpose utility functions +Revision: $Rev: 18102 $ +---------------------------END-OF-HEADER------------------------------ +*/ + +#ifndef SEGGER_H // Guard against multiple inclusion +#define SEGGER_H + +#include // For va_list. +#include "Global.h" // Type definitions: U8, U16, U32, I8, I16, I32 + +#if defined(__cplusplus) +extern "C" { /* Make sure we have C-declarations in C++ programs */ +#endif + +/********************************************************************* +* +* Keywords/specifiers +* +********************************************************************** +*/ + +#ifndef INLINE + #if (defined(__ICCARM__) || defined(__RX) || defined(__ICCRX__)) + // + // Other known compilers. + // + #define INLINE inline + #else + #if (defined(_WIN32) && !defined(__clang__)) + // + // Microsoft VC6 and newer. + // Force inlining without cost checking. + // + #define INLINE __forceinline + #elif defined(__GNUC__) || defined(__clang__) + // + // Force inlining with GCC + clang + // + #define INLINE inline __attribute__((always_inline)) + #elif (defined(__CC_ARM)) + // + // Force inlining with ARMCC (Keil) + // + #define INLINE __inline + #else + // + // Unknown compilers. + // + #define INLINE + #endif + #endif +#endif + +/********************************************************************* +* +* Function-like macros +* +********************************************************************** +*/ + +#define SEGGER_COUNTOF(a) (sizeof((a))/sizeof((a)[0])) +#define SEGGER_MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define SEGGER_MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#ifndef SEGGER_USE_PARA // Some compiler complain about unused parameters. + #define SEGGER_USE_PARA(Para) (void)Para // This works for most compilers. +#endif + +#define SEGGER_ADDR2PTR(Type, Addr) (/*lint -e(923) -e(9078)*/((Type*)((PTR_ADDR)(Addr)))) // Allow cast from address to pointer. +#define SEGGER_PTR2ADDR(p) (/*lint -e(923) -e(9078)*/((PTR_ADDR)(p))) // Allow cast from pointer to address. +#define SEGGER_PTR2PTR(Type, p) (/*lint -e(740) -e(826) -e(9079) -e(9087)*/((Type*)(p))) // Allow cast from one pointer type to another (ignore different size). +#define SEGGER_PTR_DISTANCE(p0, p1) (SEGGER_PTR2ADDR(p0) - SEGGER_PTR2ADDR(p1)) + +/********************************************************************* +* +* Defines +* +********************************************************************** +*/ + +#define SEGGER_PRINTF_FLAG_ADJLEFT (1 << 0) +#define SEGGER_PRINTF_FLAG_SIGNFORCE (1 << 1) +#define SEGGER_PRINTF_FLAG_SIGNSPACE (1 << 2) +#define SEGGER_PRINTF_FLAG_PRECEED (1 << 3) +#define SEGGER_PRINTF_FLAG_ZEROPAD (1 << 4) +#define SEGGER_PRINTF_FLAG_NEGATIVE (1 << 5) + +/********************************************************************* +* +* Types +* +********************************************************************** +*/ + +typedef struct { + char* pBuffer; + int BufferSize; + int Cnt; +} SEGGER_BUFFER_DESC; + +typedef struct { + unsigned int CacheLineSize; // 0: No Cache. Most Systems such as ARM9 use a 32 bytes cache line size. + void (*pfDMB) (void); // Optional DMB function for Data Memory Barrier to make sure all memory operations are completed. + void (*pfClean) (void *p, unsigned long NumBytes); // Optional clean function for cached memory. + void (*pfInvalidate)(void *p, unsigned long NumBytes); // Optional invalidate function for cached memory. +} SEGGER_CACHE_CONFIG; + +typedef struct SEGGER_SNPRINTF_CONTEXT_struct SEGGER_SNPRINTF_CONTEXT; + +struct SEGGER_SNPRINTF_CONTEXT_struct { + void* pContext; // Application specific context. + SEGGER_BUFFER_DESC* pBufferDesc; // Buffer descriptor to use for output. + void (*pfFlush)(SEGGER_SNPRINTF_CONTEXT* pContext); // Callback executed once the buffer is full. Callback decides if the buffer gets cleared to store more or not. +}; + +typedef struct { + void (*pfStoreChar) (SEGGER_BUFFER_DESC* pBufferDesc, SEGGER_SNPRINTF_CONTEXT* pContext, char c); + int (*pfPrintUnsigned) (SEGGER_BUFFER_DESC* pBufferDesc, SEGGER_SNPRINTF_CONTEXT* pContext, U32 v, unsigned Base, char Flags, int Width, int Precision); + int (*pfPrintInt) (SEGGER_BUFFER_DESC* pBufferDesc, SEGGER_SNPRINTF_CONTEXT* pContext, I32 v, unsigned Base, char Flags, int Width, int Precision); +} SEGGER_PRINTF_API; + +typedef void (*SEGGER_pFormatter)(SEGGER_BUFFER_DESC* pBufferDesc, SEGGER_SNPRINTF_CONTEXT* pContext, const SEGGER_PRINTF_API* pApi, va_list* pParamList, char Lead, int Width, int Precision); + +typedef struct SEGGER_PRINTF_FORMATTER { + struct SEGGER_PRINTF_FORMATTER* pNext; // Pointer to next formatter. + SEGGER_pFormatter pfFormatter; // Formatter function. + char Specifier; // Format specifier. +} SEGGER_PRINTF_FORMATTER; + +typedef struct { + U32 (*pfGetHPTimestamp)(void); // Mandatory, pfGetHPTimestamp + int (*pfGetUID) (U8 abUID[16]); // Optional, pfGetUID +} SEGGER_BSP_API; + +/********************************************************************* +* +* Utility functions +* +********************************************************************** +*/ + +// +// Memory operations. +// +void SEGGER_ARM_memcpy(void* pDest, const void* pSrc, int NumBytes); +void SEGGER_memcpy (void* pDest, const void* pSrc, unsigned NumBytes); +void SEGGER_memxor (void* pDest, const void* pSrc, unsigned NumBytes); + +// +// String functions. +// +int SEGGER_atoi (const char* s); +int SEGGER_isalnum (int c); +int SEGGER_isalpha (int c); +unsigned SEGGER_strlen (const char* s); +int SEGGER_tolower (int c); +int SEGGER_strcasecmp (const char* sText1, const char* sText2); +int SEGGER_strncasecmp(const char *sText1, const char *sText2, unsigned Count); + +// +// Buffer/printf related. +// +void SEGGER_StoreChar (SEGGER_BUFFER_DESC* pBufferDesc, char c); +void SEGGER_PrintUnsigned(SEGGER_BUFFER_DESC* pBufferDesc, U32 v, unsigned Base, int Precision); +void SEGGER_PrintInt (SEGGER_BUFFER_DESC* pBufferDesc, I32 v, unsigned Base, int Precision); +int SEGGER_snprintf (char* pBuffer, int BufferSize, const char* sFormat, ...); +int SEGGER_vsnprintf (char* pBuffer, int BufferSize, const char* sFormat, va_list ParamList); +int SEGGER_vsnprintfEx (SEGGER_SNPRINTF_CONTEXT* pContext, const char* sFormat, va_list ParamList); + +int SEGGER_PRINTF_AddFormatter (SEGGER_PRINTF_FORMATTER* pFormatter, SEGGER_pFormatter pfFormatter, char c); +void SEGGER_PRINTF_AddDoubleFormatter (void); +void SEGGER_PRINTF_AddIPFormatter (void); +void SEGGER_PRINTF_AddBLUEFormatter (void); +void SEGGER_PRINTF_AddCONNECTFormatter(void); +void SEGGER_PRINTF_AddSSLFormatter (void); +void SEGGER_PRINTF_AddSSHFormatter (void); +void SEGGER_PRINTF_AddHTMLFormatter (void); + +// +// BSP abstraction API. +// +int SEGGER_BSP_GetUID (U8 abUID[16]); +int SEGGER_BSP_GetUID32(U32* pUID); +void SEGGER_BSP_SetAPI (const SEGGER_BSP_API* pAPI); +void SEGGER_BSP_SeedUID (void); + +// +// Other API. +// +void SEGGER_VERSION_GetString(char acText[8], unsigned Version); + +#if defined(__cplusplus) +} /* Make sure we have C-declarations in C++ programs */ +#endif + +#endif // Avoid multiple inclusion + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_RTT.c b/bsp/projects/common/segger/SEGGER_RTT.c new file mode 100644 index 0000000..ad7ccb4 --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_RTT.c @@ -0,0 +1,2095 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT.c +Purpose : Implementation of SEGGER real-time transfer (RTT) which + allows real-time communication on targets which support + debugger memory accesses while the CPU is running. +Revision: $Rev: 25842 $ + +Additional information: + Type "int" is assumed to be 32-bits in size + H->T Host to target communication + T->H Target to host communication + + RTT channel 0 is always present and reserved for Terminal usage. + Name is fixed to "Terminal" + + Effective buffer size: SizeOfBuffer - 1 + + WrOff == RdOff: Buffer is empty + WrOff == (RdOff - 1): Buffer is full + WrOff > RdOff: Free space includes wrap-around + WrOff < RdOff: Used space includes wrap-around + (WrOff == (SizeOfBuffer - 1)) && (RdOff == 0): + Buffer full and wrap-around after next byte + + +---------------------------------------------------------------------- +*/ + +#include "SEGGER_RTT.h" + +#include // for memcpy + +/********************************************************************* +* +* Configuration, default values +* +********************************************************************** +*/ + +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #ifdef SEGGER_RTT_CB_ALIGN + #error "Custom SEGGER_RTT_CB_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_BUFFER_ALIGN + #error "Custom SEGGER_RTT_BUFFER_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_PUT_CB_SECTION + #error "Custom SEGGER_RTT_PUT_CB_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_PUT_BUFFER_SECTION + #error "Custom SEGGER_RTT_PUT_BUFFER_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_BUFFER_ALIGNMENT + #error "Custom SEGGER_RTT_BUFFER_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_ALIGNMENT + #error "Custom SEGGER_RTT_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif +#endif + +#ifndef BUFFER_SIZE_UP + #define BUFFER_SIZE_UP 1024 // Size of the buffer for terminal output of target, up to host +#endif + +#ifndef BUFFER_SIZE_DOWN + #define BUFFER_SIZE_DOWN 16 // Size of the buffer for terminal input to target from host (Usually keyboard input) +#endif + +#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS + #define SEGGER_RTT_MAX_NUM_UP_BUFFERS 2 // Number of up-buffers (T->H) available on this target +#endif + +#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS + #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS 2 // Number of down-buffers (H->T) available on this target +#endif + +#ifndef SEGGER_RTT_BUFFER_SECTION + #if defined(SEGGER_RTT_SECTION) + #define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION + #endif +#endif + +#ifndef SEGGER_RTT_ALIGNMENT + #define SEGGER_RTT_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE +#endif + +#ifndef SEGGER_RTT_BUFFER_ALIGNMENT + #define SEGGER_RTT_BUFFER_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE +#endif + +#ifndef SEGGER_RTT_MODE_DEFAULT + #define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP +#endif + +#ifndef SEGGER_RTT_LOCK + #define SEGGER_RTT_LOCK() +#endif + +#ifndef SEGGER_RTT_UNLOCK + #define SEGGER_RTT_UNLOCK() +#endif + +#ifndef STRLEN + #define STRLEN(a) strlen((a)) +#endif + +#ifndef STRCPY + #define STRCPY(pDest, pSrc) strcpy((pDest), (pSrc)) +#endif + +#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP + #define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 +#endif + +#ifndef SEGGER_RTT_MEMCPY + #ifdef MEMCPY + #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) MEMCPY((pDest), (pSrc), (NumBytes)) + #else + #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) memcpy((pDest), (pSrc), (NumBytes)) + #endif +#endif + +#ifndef MIN + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif +// +// For some environments, NULL may not be defined until certain headers are included +// +#ifndef NULL + #define NULL 0 +#endif + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ +#if (defined __ICCARM__) || (defined __ICCRX__) + #define RTT_PRAGMA(P) _Pragma(#P) +#endif + +#if SEGGER_RTT_ALIGNMENT || SEGGER_RTT_BUFFER_ALIGNMENT + #if ((defined __GNUC__) || (defined __clang__)) + #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment))) + #elif (defined __ICCARM__) || (defined __ICCRX__) + #define PRAGMA(A) _Pragma(#A) +#define SEGGER_RTT_ALIGN(Var, Alignment) RTT_PRAGMA(data_alignment=Alignment) \ + Var + #elif (defined __CC_ARM) + #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment))) + #else + #error "Alignment not supported for this compiler." + #endif +#else + #define SEGGER_RTT_ALIGN(Var, Alignment) Var +#endif + +#if defined(SEGGER_RTT_SECTION) || defined (SEGGER_RTT_BUFFER_SECTION) + #if ((defined __GNUC__) || (defined __clang__)) + #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section))) Var + #elif (defined __ICCARM__) || (defined __ICCRX__) +#define SEGGER_RTT_PUT_SECTION(Var, Section) RTT_PRAGMA(location=Section) \ + Var + #elif (defined __CC_ARM) + #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section), zero_init)) Var + #else + #error "Section placement not supported for this compiler." + #endif +#else + #define SEGGER_RTT_PUT_SECTION(Var, Section) Var +#endif + +#if SEGGER_RTT_ALIGNMENT + #define SEGGER_RTT_CB_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_ALIGNMENT) +#else + #define SEGGER_RTT_CB_ALIGN(Var) Var +#endif + +#if SEGGER_RTT_BUFFER_ALIGNMENT + #define SEGGER_RTT_BUFFER_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_BUFFER_ALIGNMENT) +#else + #define SEGGER_RTT_BUFFER_ALIGN(Var) Var +#endif + + +#if defined(SEGGER_RTT_SECTION) + #define SEGGER_RTT_PUT_CB_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_SECTION) +#else + #define SEGGER_RTT_PUT_CB_SECTION(Var) Var +#endif + +#if defined(SEGGER_RTT_BUFFER_SECTION) + #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_BUFFER_SECTION) +#else + #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) Var +#endif + +/********************************************************************* +* +* Static const data +* +********************************************************************** +*/ + +static unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/********************************************************************* +* +* Static data +* +********************************************************************** +*/ + +// +// RTT Control Block and allocate buffers for channel 0 +// +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #if ((defined __GNUC__) || (defined __clang__)) + SEGGER_RTT_CB _SEGGER_RTT __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + static char _acUpBuffer [SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)] __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + static char _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)] __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + #else + #error "Don't know how to place _SEGGER_RTT, _acUpBuffer, _acDownBuffer cache-line aligned" + #endif +#else + SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT)); + SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer [BUFFER_SIZE_UP])); + SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN])); +#endif + +static unsigned char _ActiveTerminal; + +/********************************************************************* +* +* Static functions +* +********************************************************************** +*/ + +/********************************************************************* +* +* _DoInit() +* +* Function description +* Initializes the control block an buffers. +* May only be called via INIT() to avoid overriding settings. +* +*/ +#define INIT() { \ + volatile SEGGER_RTT_CB* pRTTCBInit; \ + pRTTCBInit = (volatile SEGGER_RTT_CB*)((char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); \ + do { \ + if (pRTTCBInit->acID[0] == '\0') { \ + _DoInit(); \ + } \ + } while (0); \ + } + +static void _DoInit(void) { + volatile SEGGER_RTT_CB* p; // Volatile to make sure that compiler cannot change the order of accesses to the control block + static const char _aInitStr[] = "\0\0\0\0\0\0TTR REGGES"; // Init complete ID string to make sure that things also work if RTT is linked to a no-init memory area + unsigned i; + // + // Initialize control block + // + p = (volatile SEGGER_RTT_CB*)((char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access control block uncached so that nothing in the cache ever becomes dirty and all changes are visible in HW directly + memset((SEGGER_RTT_CB*)p, 0, sizeof(_SEGGER_RTT)); // Make sure that the RTT CB is always zero initialized. + p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS; + p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS; + // + // Initialize up buffer 0 + // + p->aUp[0].sName = "Terminal"; + p->aUp[0].pBuffer = _acUpBuffer; + p->aUp[0].SizeOfBuffer = BUFFER_SIZE_UP; + p->aUp[0].RdOff = 0u; + p->aUp[0].WrOff = 0u; + p->aUp[0].Flags = SEGGER_RTT_MODE_DEFAULT; + // + // Initialize down buffer 0 + // + p->aDown[0].sName = "Terminal"; + p->aDown[0].pBuffer = _acDownBuffer; + p->aDown[0].SizeOfBuffer = BUFFER_SIZE_DOWN; + p->aDown[0].RdOff = 0u; + p->aDown[0].WrOff = 0u; + p->aDown[0].Flags = SEGGER_RTT_MODE_DEFAULT; + // + // Finish initialization of the control block. + // Copy Id string backwards to make sure that "SEGGER RTT" is not found in initializer memory (usually flash), + // as this would cause J-Link to "find" the control block at a wrong address. + // + RTT__DMB(); // Force order of memory accesses for cores that may perform out-of-order memory accesses + for (i = 0; i < sizeof(_aInitStr) - 1; ++i) { + p->acID[i] = _aInitStr[sizeof(_aInitStr) - 2 - i]; // Skip terminating \0 at the end of the array + } + RTT__DMB(); // Force order of memory accesses for cores that may perform out-of-order memory accesses +} + +/********************************************************************* +* +* _WriteBlocking() +* +* Function description +* Stores a specified number of characters in SEGGER RTT ring buffer +* and updates the associated write pointer which is periodically +* read by the host. +* The caller is responsible for managing the write chunk sizes as +* _WriteBlocking() will block until all data has been posted successfully. +* +* Parameters +* pRing Ring buffer to post to. +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* >= 0 - Number of bytes written into buffer. +*/ +static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, unsigned NumBytes) { + unsigned NumBytesToWrite; + unsigned NumBytesWritten; + unsigned RdOff; + unsigned WrOff; + volatile char* pDst; + // + // Write data to buffer and handle wrap-around if necessary + // + NumBytesWritten = 0u; + WrOff = pRing->WrOff; + do { + RdOff = pRing->RdOff; // May be changed by host (debug probe) in the meantime + if (RdOff > WrOff) { + NumBytesToWrite = RdOff - WrOff - 1u; + } else { + NumBytesToWrite = pRing->SizeOfBuffer - (WrOff - RdOff + 1u); + } + NumBytesToWrite = MIN(NumBytesToWrite, (pRing->SizeOfBuffer - WrOff)); // Number of bytes that can be written until buffer wrap-around + NumBytesToWrite = MIN(NumBytesToWrite, NumBytes); + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesWritten += NumBytesToWrite; + NumBytes -= NumBytesToWrite; + WrOff += NumBytesToWrite; + while (NumBytesToWrite--) { + *pDst++ = *pBuffer++; + }; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pBuffer, NumBytesToWrite); + NumBytesWritten += NumBytesToWrite; + pBuffer += NumBytesToWrite; + NumBytes -= NumBytesToWrite; + WrOff += NumBytesToWrite; +#endif + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0u; + } + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; + } while (NumBytes); + return NumBytesWritten; +} + +/********************************************************************* +* +* _WriteNoCheck() +* +* Function description +* Stores a specified number of characters in SEGGER RTT ring buffer +* and updates the associated write pointer which is periodically +* read by the host. +* It is callers responsibility to make sure data actually fits in buffer. +* +* Parameters +* pRing Ring buffer to post to. +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Notes +* (1) If there might not be enough space in the "Up"-buffer, call _WriteBlocking +*/ +static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsigned NumBytes) { + unsigned NumBytesAtOnce; + unsigned WrOff; + unsigned Rem; + volatile char* pDst; + + WrOff = pRing->WrOff; + Rem = pRing->SizeOfBuffer - WrOff; + if (Rem > NumBytes) { + // + // All data fits before wrap around + // + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + WrOff += NumBytes; + while (NumBytes--) { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; +#endif + } else { + // + // We reach the end of the buffer, so need to wrap around + // +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + NumBytesAtOnce = Rem; + while (NumBytesAtOnce--) { + *pDst++ = *pData++; + }; + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + NumBytesAtOnce = NumBytes - Rem; + while (NumBytesAtOnce--) { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = NumBytes - Rem; +#else + NumBytesAtOnce = Rem; + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytesAtOnce); + NumBytesAtOnce = NumBytes - Rem; + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + SEGGER_RTT_MEMCPY((void*)pDst, pData + Rem, NumBytesAtOnce); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = NumBytesAtOnce; +#endif + } +} + +/********************************************************************* +* +* _PostTerminalSwitch() +* +* Function description +* Switch terminal to the given terminal ID. It is the caller's +* responsibility to ensure the terminal ID is correct and there is +* enough space in the buffer for this to complete successfully. +* +* Parameters +* pRing Ring buffer to post to. +* TerminalId Terminal ID to switch to. +*/ +static void _PostTerminalSwitch(SEGGER_RTT_BUFFER_UP* pRing, unsigned char TerminalId) { + unsigned char ac[2]; + + ac[0] = 0xFFu; + ac[1] = _aTerminalId[TerminalId]; // Caller made already sure that TerminalId does not exceed our terminal limit + _WriteBlocking(pRing, (const char*)ac, 2u); +} + +/********************************************************************* +* +* _GetAvailWriteSpace() +* +* Function description +* Returns the number of bytes that can be written to the ring +* buffer without blocking. +* +* Parameters +* pRing Ring buffer to check. +* +* Return value +* Number of bytes that are free in the buffer. +*/ +static unsigned _GetAvailWriteSpace(SEGGER_RTT_BUFFER_UP* pRing) { + unsigned RdOff; + unsigned WrOff; + unsigned r; + // + // Avoid warnings regarding volatile access order. It's not a problem + // in this case, but dampen compiler enthusiasm. + // + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + if (RdOff <= WrOff) { + r = pRing->SizeOfBuffer - 1u - WrOff + RdOff; + } else { + r = RdOff - WrOff - 1u; + } + return r; +} + +/********************************************************************* +* +* Public code +* +********************************************************************** +*/ + +/********************************************************************* +* +* SEGGER_RTT_ReadUpBufferNoLock() +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the application. +* Do not lock against interrupts and multiple access. +* Used to do the same operation that J-Link does, to transfer +* RTT data via other channels, such as TCP/IP or UART. +* +* Parameters +* BufferIndex Index of Up-buffer to be used. +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-up-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +* +* Additional information +* This function must not be called when J-Link might also do RTT. +*/ +unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) { + unsigned NumBytesRem; + unsigned NumBytesRead; + unsigned RdOff; + unsigned WrOff; + unsigned char* pBuffer; + SEGGER_RTT_BUFFER_UP* pRing; + volatile char* pSrc; + + INIT(); + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + pBuffer = (unsigned char*)pData; + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + NumBytesRead = 0u; + // + // Read from current read position to wrap-around of buffer, first + // + if (RdOff > WrOff) { + NumBytesRem = pRing->SizeOfBuffer - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + // + // Handle wrap-around of buffer + // + if (RdOff == pRing->SizeOfBuffer) { + RdOff = 0u; + } + } + // + // Read remaining items of buffer + // + NumBytesRem = WrOff - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + if (NumBytesRem > 0u) { + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + } + // + // Update read offset of buffer + // + if (NumBytesRead) { + pRing->RdOff = RdOff; + } + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_ReadNoLock() +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the host. +* Do not lock against interrupts and multiple access. +* +* Parameters +* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +*/ +unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) { + unsigned NumBytesRem; + unsigned NumBytesRead; + unsigned RdOff; + unsigned WrOff; + unsigned char* pBuffer; + SEGGER_RTT_BUFFER_DOWN* pRing; + volatile char* pSrc; + // + INIT(); + pRing = (SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + pBuffer = (unsigned char*)pData; + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + NumBytesRead = 0u; + // + // Read from current read position to wrap-around of buffer, first + // + if (RdOff > WrOff) { + NumBytesRem = pRing->SizeOfBuffer - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + // + // Handle wrap-around of buffer + // + if (RdOff == pRing->SizeOfBuffer) { + RdOff = 0u; + } + } + // + // Read remaining items of buffer + // + NumBytesRem = WrOff - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + if (NumBytesRem > 0u) { + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + } + if (NumBytesRead) { + pRing->RdOff = RdOff; + } + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_ReadUpBuffer +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the application. +* Used to do the same operation that J-Link does, to transfer +* RTT data via other channels, such as TCP/IP or UART. +* +* Parameters +* BufferIndex Index of Up-buffer to be used. +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-up-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +* +* Additional information +* This function must not be called when J-Link might also do RTT. +* This function locks against all other RTT operations. I.e. during +* the read operation, writing is also locked. +* If only one consumer reads from the up buffer, +* call sEGGER_RTT_ReadUpBufferNoLock() instead. +*/ +unsigned SEGGER_RTT_ReadUpBuffer(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) { + unsigned NumBytesRead; + + SEGGER_RTT_LOCK(); + // + // Call the non-locking read function + // + NumBytesRead = SEGGER_RTT_ReadUpBufferNoLock(BufferIndex, pBuffer, BufferSize); + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_Read +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the host. +* +* Parameters +* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +*/ +unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) { + unsigned NumBytesRead; + + SEGGER_RTT_LOCK(); + // + // Call the non-locking read function + // + NumBytesRead = SEGGER_RTT_ReadNoLock(BufferIndex, pBuffer, BufferSize); + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteWithOverwriteNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block. +* SEGGER_RTT_WriteWithOverwriteNoLock does not lock the application +* and overwrites data if the data does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, data is overwritten. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +* (3) Do not use SEGGER_RTT_WriteWithOverwriteNoLock if a J-Link +* connection reads RTT data. +*/ +void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + volatile char* pDst; + // + // Get "to-host" ring buffer and copy some elements into local variables. + // + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Check if we will overwrite data and need to adjust the RdOff. + // + if (pRing->WrOff == pRing->RdOff) { + Avail = pRing->SizeOfBuffer - 1u; + } else if ( pRing->WrOff < pRing->RdOff) { + Avail = pRing->RdOff - pRing->WrOff - 1u; + } else { + Avail = pRing->RdOff - pRing->WrOff - 1u + pRing->SizeOfBuffer; + } + if (NumBytes > Avail) { + pRing->RdOff += (NumBytes - Avail); + while (pRing->RdOff >= pRing->SizeOfBuffer) { + pRing->RdOff -= pRing->SizeOfBuffer; + } + } + // + // Write all data, no need to check the RdOff, but possibly handle multiple wrap-arounds + // + Avail = pRing->SizeOfBuffer - pRing->WrOff; + do { + if (Avail > NumBytes) { + // + // Last round + // + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + Avail = NumBytes; + while (NumBytes--) { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff += Avail; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff += NumBytes; +#endif + break; + } else { + // + // Wrap-around necessary, write until wrap-around and reset WrOff + // + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytes -= Avail; + while (Avail--) { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = 0; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, Avail); + pData += Avail; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = 0; + NumBytes -= Avail; +#endif + Avail = (pRing->SizeOfBuffer - 1); + } + } while (NumBytes); +} + +/********************************************************************* +* +* SEGGER_RTT_WriteSkipNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* SEGGER_RTT_WriteSkipNoLock does not lock the application and +* skips all data, if the data does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* MUST be > 0!!! +* This is done for performance reasons, so no initial check has do be done. +* +* Return value +* 1: Data has been copied +* 0: No space, data has not been copied +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, all data is dropped. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ +#if (RTT_USE_ASM == 0) +unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + unsigned RdOff; + unsigned WrOff; + unsigned Rem; + volatile char* pDst; + // + // Cases: + // 1) RdOff <= WrOff => Space until wrap-around is sufficient + // 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks) + // 3) RdOff < WrOff => No space in buf + // 4) RdOff > WrOff => Space is sufficient + // 5) RdOff > WrOff => No space in buf + // + // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough + // + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + if (RdOff <= WrOff) { // Case 1), 2) or 3) + Avail = pRing->SizeOfBuffer - WrOff - 1u; // Space until wrap-around (assume 1 byte not usable for case that RdOff == 0) + if (Avail >= NumBytes) { // Case 1)? +CopyStraight: + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + memcpy((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; + return 1; + } + Avail += RdOff; // Space incl. wrap-around + if (Avail >= NumBytes) { // Case 2? => If not, we have case 3) (does not fit) + Rem = pRing->SizeOfBuffer - WrOff; // Space until end of buffer + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + memcpy((void*)pDst, pData, Rem); // Copy 1st chunk + NumBytes -= Rem; + // + // Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used + // But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the last element + // In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks + // Therefore, check if 2nd memcpy is necessary at all + // + if (NumBytes) { + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + memcpy((void*)pDst, pData + Rem, NumBytes); + } + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = NumBytes; + return 1; + } + } else { // Potential case 4) + Avail = RdOff - WrOff - 1u; + if (Avail >= NumBytes) { // Case 4)? => If not, we have case 5) (does not fit) + goto CopyStraight; + } + } + return 0; // No space in buffer +} +#endif + +/********************************************************************* +* +* SEGGER_RTT_WriteDownBufferNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block inside a buffer. +* SEGGER_RTT_WriteDownBufferNoLock does not lock the application. +* Used to do the same operation that J-Link does, to transfer +* RTT data from other channels, such as TCP/IP or UART. +* +* Parameters +* BufferIndex Index of "Down"-buffer to be used. +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Down"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +* +* Additional information +* This function must not be called when J-Link might also do RTT. +*/ +unsigned SEGGER_RTT_WriteDownBufferNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + unsigned Avail; + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + // + // Get "to-target" ring buffer. + // It is save to cast that to a "to-host" buffer. Up and Down buffer differ in volatility of offsets that might be modified by J-Link. + // + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // How we output depends upon the mode... + // + switch (pRing->Flags) { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother. + // + Avail = _GetAvailWriteSpace(pRing); + if (Avail < NumBytes) { + Status = 0u; + } else { + Status = NumBytes; + _WriteNoCheck(pRing, pData, NumBytes); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode, trim to what we can output without blocking. + // + Avail = _GetAvailWriteSpace(pRing); + Status = Avail < NumBytes ? Avail : NumBytes; + _WriteNoCheck(pRing, pData, Status); + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + Status = _WriteBlocking(pRing, pData, NumBytes); + break; + default: + Status = 0u; + break; + } + // + // Finish up. + // + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* SEGGER_RTT_WriteNoLock does not lock the application. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ +unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + unsigned Avail; + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + // + // Get "to-host" ring buffer. + // + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // How we output depends upon the mode... + // + switch (pRing->Flags) { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother. + // + Avail = _GetAvailWriteSpace(pRing); + if (Avail < NumBytes) { + Status = 0u; + } else { + Status = NumBytes; + _WriteNoCheck(pRing, pData, NumBytes); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode, trim to what we can output without blocking. + // + Avail = _GetAvailWriteSpace(pRing); + Status = Avail < NumBytes ? Avail : NumBytes; + _WriteNoCheck(pRing, pData, Status); + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + Status = _WriteBlocking(pRing, pData, NumBytes); + break; + default: + Status = 0u; + break; + } + // + // Finish up. + // + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteDownBuffer +* +* Function description +* Stores a specified number of characters in SEGGER RTT control block in a buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Down"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +* +* Additional information +* This function must not be called when J-Link might also do RTT. +* This function locks against all other RTT operations. I.e. during +* the write operation, writing from the application is also locked. +* If only one consumer writes to the down buffer, +* call SEGGER_RTT_WriteDownBufferNoLock() instead. +*/ +unsigned SEGGER_RTT_WriteDownBuffer(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + + INIT(); + SEGGER_RTT_LOCK(); + Status = SEGGER_RTT_WriteDownBufferNoLock(BufferIndex, pBuffer, NumBytes); // Call the non-locking write function + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_Write +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +*/ +unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + + INIT(); + SEGGER_RTT_LOCK(); + Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes); // Call the non-locking write function + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteString +* +* Function description +* Stores string in SEGGER RTT control block. +* This data is read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* s Pointer to string. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +* (2) String passed to this function has to be \0 terminated +* (3) \0 termination character is *not* stored in RTT buffer +*/ +unsigned SEGGER_RTT_WriteString(unsigned BufferIndex, const char* s) { + unsigned Len; + + Len = STRLEN(s); + return SEGGER_RTT_Write(BufferIndex, s, Len); +} + +/********************************************************************* +* +* SEGGER_RTT_PutCharSkipNoLock +* +* Function description +* Stores a single character/byte in SEGGER RTT buffer. +* SEGGER_RTT_PutCharSkipNoLock does not lock the application and +* skips the byte, if it does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* c Byte to be stored. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, the character is dropped. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ + +unsigned SEGGER_RTT_PutCharSkipNoLock(unsigned BufferIndex, char c) { + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0; + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } else { + Status = 0; + } + // + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_PutCharSkip +* +* Function description +* Stores a single character/byte in SEGGER RTT buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* c Byte to be stored. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, the character is dropped. +*/ + +unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) { + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Prepare + // + INIT(); + SEGGER_RTT_LOCK(); + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0; + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } else { + Status = 0; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return Status; +} + + /********************************************************************* +* +* SEGGER_RTT_PutChar +* +* Function description +* Stores a single character/byte in SEGGER RTT buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* c Byte to be stored. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) Data is stored according to buffer flags. +*/ + +unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) { + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Prepare + // + INIT(); + SEGGER_RTT_LOCK(); + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0; + } + // + // Wait for free space if mode is set to blocking + // + if (pRing->Flags == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { + while (WrOff == pRing->RdOff) { + ; + } + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } else { + Status = 0; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_GetKey +* +* Function description +* Reads one character from the SEGGER RTT buffer. +* Host has previously stored data there. +* +* Return value +* < 0 - No character available (buffer empty). +* >= 0 - Character which has been read. (Possible values: 0 - 255) +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0. +*/ +int SEGGER_RTT_GetKey(void) { + char c; + int r; + + r = (int)SEGGER_RTT_Read(0u, &c, 1u); + if (r == 1) { + r = (int)(unsigned char)c; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_WaitKey +* +* Function description +* Waits until at least one character is avaible in the SEGGER RTT buffer. +* Once a character is available, it is read and this function returns. +* +* Return value +* >=0 - Character which has been read. +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0 +* (2) This function is blocking if no character is present in RTT buffer +*/ +int SEGGER_RTT_WaitKey(void) { + int r; + + do { + r = SEGGER_RTT_GetKey(); + } while (r < 0); + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_HasKey +* +* Function description +* Checks if at least one character for reading is available in the SEGGER RTT buffer. +* +* Return value +* == 0 - No characters are available to read. +* == 1 - At least one character is available. +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0 +*/ +int SEGGER_RTT_HasKey(void) { + SEGGER_RTT_BUFFER_DOWN* pRing; + unsigned RdOff; + int r; + + INIT(); + pRing = (SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + RdOff = pRing->RdOff; + if (RdOff != pRing->WrOff) { + r = 1; + } else { + r = 0; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_HasData +* +* Function description +* Check if there is data from the host in the given buffer. +* +* Return value: +* ==0: No data +* !=0: Data in buffer +* +*/ +unsigned SEGGER_RTT_HasData(unsigned BufferIndex) { + SEGGER_RTT_BUFFER_DOWN* pRing; + unsigned v; + + pRing = (SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + v = pRing->WrOff; + return v - pRing->RdOff; +} + +/********************************************************************* +* +* SEGGER_RTT_HasDataUp +* +* Function description +* Check if there is data remaining to be sent in the given buffer. +* +* Return value: +* ==0: No data +* !=0: Data in buffer +* +*/ +unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) { + SEGGER_RTT_BUFFER_UP* pRing; + unsigned v; + + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + v = pRing->RdOff; + return pRing->WrOff - v; +} + +/********************************************************************* +* +* SEGGER_RTT_AllocDownBuffer +* +* Function description +* Run-time configuration of the next down-buffer (H->T). +* The next buffer, which is not used yet is configured. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 - O.K. Buffer Index +* < 0 - Error +*/ +int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int BufferIndex; + volatile SEGGER_RTT_CB* pRTTCB; + + INIT(); + SEGGER_RTT_LOCK(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + BufferIndex = 0; + do { + if (pRTTCB->aDown[BufferIndex].pBuffer == NULL) { + break; + } + BufferIndex++; + } while (BufferIndex < pRTTCB->MaxNumDownBuffers); + if (BufferIndex < pRTTCB->MaxNumDownBuffers) { + pRTTCB->aDown[BufferIndex].sName = sName; + pRTTCB->aDown[BufferIndex].pBuffer = (char*)pBuffer; + pRTTCB->aDown[BufferIndex].SizeOfBuffer = BufferSize; + pRTTCB->aDown[BufferIndex].RdOff = 0u; + pRTTCB->aDown[BufferIndex].WrOff = 0u; + pRTTCB->aDown[BufferIndex].Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + } else { + BufferIndex = -1; + } + SEGGER_RTT_UNLOCK(); + return BufferIndex; +} + +/********************************************************************* +* +* SEGGER_RTT_AllocUpBuffer +* +* Function description +* Run-time configuration of the next up-buffer (T->H). +* The next buffer, which is not used yet is configured. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 - O.K. Buffer Index +* < 0 - Error +*/ +int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int BufferIndex; + volatile SEGGER_RTT_CB* pRTTCB; + + INIT(); + SEGGER_RTT_LOCK(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + BufferIndex = 0; + do { + if (pRTTCB->aUp[BufferIndex].pBuffer == NULL) { + break; + } + BufferIndex++; + } while (BufferIndex < pRTTCB->MaxNumUpBuffers); + if (BufferIndex < pRTTCB->MaxNumUpBuffers) { + pRTTCB->aUp[BufferIndex].sName = sName; + pRTTCB->aUp[BufferIndex].pBuffer = (char*)pBuffer; + pRTTCB->aUp[BufferIndex].SizeOfBuffer = BufferSize; + pRTTCB->aUp[BufferIndex].RdOff = 0u; + pRTTCB->aUp[BufferIndex].WrOff = 0u; + pRTTCB->aUp[BufferIndex].Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + } else { + BufferIndex = -1; + } + SEGGER_RTT_UNLOCK(); + return BufferIndex; +} + +/********************************************************************* +* +* SEGGER_RTT_ConfigUpBuffer +* +* Function description +* Run-time configuration of a specific up-buffer (T->H). +* Buffer to be configured is specified by index. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* BufferIndex Index of the buffer to configure. +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 - O.K. +* < 0 - Error +* +* Additional information +* Buffer 0 is configured on compile-time. +* May only be called once per buffer. +* Buffer name and flags can be reconfigured using the appropriate functions. +*/ +int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + if (BufferIndex) { + pUp->sName = sName; + pUp->pBuffer = (char*)pBuffer; + pUp->SizeOfBuffer = BufferSize; + pUp->RdOff = 0u; + pUp->WrOff = 0u; + } + pUp->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_ConfigDownBuffer +* +* Function description +* Run-time configuration of a specific down-buffer (H->T). +* Buffer to be configured is specified by index. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* BufferIndex Index of the buffer to configure. +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 O.K. +* < 0 Error +* +* Additional information +* Buffer 0 is configured on compile-time. +* May only be called once per buffer. +* Buffer name and flags can be reconfigured using the appropriate functions. +*/ +int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + if (BufferIndex) { + pDown->sName = sName; + pDown->pBuffer = (char*)pBuffer; + pDown->SizeOfBuffer = BufferSize; + pDown->RdOff = 0u; + pDown->WrOff = 0u; + } + pDown->Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetNameUpBuffer +* +* Function description +* Run-time configuration of a specific up-buffer name (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* sName Pointer to a constant name string. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + pUp->sName = sName; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetNameDownBuffer +* +* Function description +* Run-time configuration of a specific Down-buffer name (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* sName Pointer to a constant name string. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + pDown->sName = sName; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetFlagsUpBuffer +* +* Function description +* Run-time configuration of specific up-buffer flags (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer. +* Flags Flags to set for the buffer. +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + pUp->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetFlagsDownBuffer +* +* Function description +* Run-time configuration of specific Down-buffer flags (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* Flags Flags to set for the buffer. +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags) { + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + pDown->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_Init +* +* Function description +* Initializes the RTT Control Block. +* Should be used in RAM targets, at start of the application. +* +*/ +void SEGGER_RTT_Init (void) { + _DoInit(); +} + +/********************************************************************* +* +* SEGGER_RTT_SetTerminal +* +* Function description +* Sets the terminal to be used for output on channel 0. +* +* Parameters +* TerminalId Index of the terminal. +* +* Return value +* >= 0 O.K. +* < 0 Error (e.g. if RTT is configured for non-blocking mode and there was no space in the buffer to set the new terminal Id) +* +* Notes +* (1) Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed +*/ +int SEGGER_RTT_SetTerminal (unsigned char TerminalId) { + unsigned char ac[2]; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + int r; + + INIT(); + r = 0; + ac[0] = 0xFFu; + if (TerminalId < sizeof(_aTerminalId)) { // We only support a certain number of channels + ac[1] = _aTerminalId[TerminalId]; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in buffer does not change downwards after checking and before writing + if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { + _ActiveTerminal = TerminalId; + _WriteBlocking(pRing, (const char*)ac, 2u); + } else { // Skipping mode or trim mode? => We cannot trim this command so handling is the same for both modes + Avail = _GetAvailWriteSpace(pRing); + if (Avail >= 2) { + _ActiveTerminal = TerminalId; // Only change active terminal in case of success + _WriteNoCheck(pRing, (const char*)ac, 2u); + } else { + r = -1; + } + } + SEGGER_RTT_UNLOCK(); + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_TerminalOut +* +* Function description +* Writes a string to the given terminal +* without changing the terminal for channel 0. +* +* Parameters +* TerminalId Index of the terminal. +* s String to be printed on the terminal. +* +* Return value +* >= 0 - Number of bytes written. +* < 0 - Error. +* +*/ +int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s) { + int Status; + unsigned FragLen; + unsigned Avail; + SEGGER_RTT_BUFFER_UP* pRing; + // + INIT(); + // + // Validate terminal ID. + // + if (TerminalId < (char)sizeof(_aTerminalId)) { // We only support a certain number of channels + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + // + // Need to be able to change terminal, write data, change back. + // Compute the fixed and variable sizes. + // + FragLen = STRLEN(s); + // + // How we output depends upon the mode... + // + SEGGER_RTT_LOCK(); + Avail = _GetAvailWriteSpace(pRing); + switch (pRing->Flags & SEGGER_RTT_MODE_MASK) { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother switching terminals at all. + // + if (Avail < (FragLen + 4u)) { + Status = 0; + } else { + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, FragLen); + _PostTerminalSwitch(pRing, _ActiveTerminal); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode and there is not enough space for everything, + // trim the output but always include the terminal switch. If no room + // for terminal switch, skip that totally. + // + if (Avail < 4u) { + Status = -1; + } else { + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, (FragLen < (Avail - 4u)) ? FragLen : (Avail - 4u)); + _PostTerminalSwitch(pRing, _ActiveTerminal); + } + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, FragLen); + _PostTerminalSwitch(pRing, _ActiveTerminal); + break; + default: + Status = -1; + break; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + } else { + Status = -1; + } + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_GetAvailWriteSpace +* +* Function description +* Returns the number of bytes available in the ring buffer. +* +* Parameters +* BufferIndex Index of the up buffer. +* +* Return value +* Number of bytes that are free in the selected up buffer. +*/ +unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex) { + SEGGER_RTT_BUFFER_UP* pRing; + + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + return _GetAvailWriteSpace(pRing); +} + + +/********************************************************************* +* +* SEGGER_RTT_GetBytesInBuffer() +* +* Function description +* Returns the number of bytes currently used in the up buffer. +* +* Parameters +* BufferIndex Index of the up buffer. +* +* Return value +* Number of bytes that are used in the buffer. +*/ +unsigned SEGGER_RTT_GetBytesInBuffer(unsigned BufferIndex) { + unsigned RdOff; + unsigned WrOff; + unsigned r; + volatile SEGGER_RTT_CB* pRTTCB; + // + // Avoid warnings regarding volatile access order. It's not a problem + // in this case, but dampen compiler enthusiasm. + // + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + RdOff = pRTTCB->aUp[BufferIndex].RdOff; + WrOff = pRTTCB->aUp[BufferIndex].WrOff; + if (RdOff <= WrOff) { + r = WrOff - RdOff; + } else { + r = pRTTCB->aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff); + } + return r; +} + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_RTT.h b/bsp/projects/common/segger/SEGGER_RTT.h new file mode 100644 index 0000000..a47b4d6 --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_RTT.h @@ -0,0 +1,492 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT.h +Purpose : Implementation of SEGGER real-time transfer which allows + real-time communication on targets which support debugger + memory accesses while the CPU is running. +Revision: $Rev: 25842 $ +---------------------------------------------------------------------- +*/ + +#ifndef SEGGER_RTT_H +#define SEGGER_RTT_H + +#include "SEGGER_RTT_Conf.h" + +/********************************************************************* +* +* Defines, defaults +* +********************************************************************** +*/ + +#ifndef RTT_USE_ASM + // + // Some cores support out-of-order memory accesses (reordering of memory accesses in the core) + // For such cores, we need to define a memory barrier to guarantee the order of certain accesses to the RTT ring buffers. + // Needed for: + // Cortex-M7 (ARMv7-M) + // Cortex-M23 (ARM-v8M) + // Cortex-M33 (ARM-v8M) + // Cortex-A/R (ARM-v7A/R) + // + // We do not explicitly check for "Embedded Studio" as the compiler in use determines what we support. + // You can use an external toolchain like IAR inside ES. So there is no point in checking for "Embedded Studio" + // + #if (defined __CROSSWORKS_ARM) // Rowley Crossworks + #define _CC_HAS_RTT_ASM_SUPPORT 1 + #if (defined __ARM_ARCH_7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #else + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + #elif (defined __ARMCC_VERSION) + // + // ARM compiler + // ARM compiler V6.0 and later is clang based. + // Our ASM part is compatible to clang. + // + #if (__ARMCC_VERSION >= 6000000) + #define _CC_HAS_RTT_ASM_SUPPORT 1 + #else + #define _CC_HAS_RTT_ASM_SUPPORT 0 + #endif + #if (defined __ARM_ARCH_6M__) // Cortex-M0 / M1 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 // No ASM support for this architecture + #elif (defined __ARM_ARCH_7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) // Cortex-A/R 32-bit ARMv7-A/R + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #else + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + #elif ((defined __GNUC__) || (defined __clang__)) + // + // GCC / Clang + // + #define _CC_HAS_RTT_ASM_SUPPORT 1 + // ARM 7/9: __ARM_ARCH_5__ / __ARM_ARCH_5E__ / __ARM_ARCH_5T__ / __ARM_ARCH_5T__ / __ARM_ARCH_5TE__ + #if (defined __ARM_ARCH_7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 // Only Cortex-M7 needs a DMB but we cannot distinguish M4 and M7 here... + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) // Cortex-A/R 32-bit ARMv7-A/R + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #else + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + #elif ((defined __IASMARM__) || (defined __ICCARM__)) + // + // IAR assembler/compiler + // + #define _CC_HAS_RTT_ASM_SUPPORT 1 + #if (__VER__ < 6300000) + #define VOLATILE + #else + #define VOLATILE volatile + #endif + #if (defined __ARM7M__) // Needed for old versions that do not know the define yet + #if (__CORE__ == __ARM7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #endif + #endif + #if (defined __ARM7EM__) + #if (__CORE__ == __ARM7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8M_BASELINE__) + #if (__CORE__ == __ARM8M_BASELINE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8M_MAINLINE__) + #if (__CORE__ == __ARM8M_MAINLINE__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8EM_MAINLINE__) + #if (__CORE__ == __ARM8EM_MAINLINE__) // Cortex-??? + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM7A__) + #if (__CORE__ == __ARM7A__) // Cortex-A 32-bit ARMv7-A + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM7R__) + #if (__CORE__ == __ARM7R__) // Cortex-R 32-bit ARMv7-R + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif +// TBD: __ARM8A__ => Cortex-A 64-bit ARMv8-A +// TBD: __ARM8R__ => Cortex-R 64-bit ARMv8-R + #else + // + // Other compilers + // + #define _CC_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + // + // If IDE and core support the ASM version, enable ASM version by default + // + #ifndef _CORE_HAS_RTT_ASM_SUPPORT + #define _CORE_HAS_RTT_ASM_SUPPORT 0 // Default for unknown cores + #endif + #if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT) + #define RTT_USE_ASM (1) + #else + #define RTT_USE_ASM (0) + #endif +#endif + +#ifndef _CORE_NEEDS_DMB + #define _CORE_NEEDS_DMB 0 +#endif + +#ifndef RTT__DMB + #if _CORE_NEEDS_DMB + #error "Don't know how to place inline assembly for DMB" + #else + #define RTT__DMB() + #endif +#endif + +#ifndef SEGGER_RTT_CPU_CACHE_LINE_SIZE + #define SEGGER_RTT_CPU_CACHE_LINE_SIZE (0) // On most target systems where RTT is used, we do not have a CPU cache, therefore 0 is a good default here +#endif + +#ifndef SEGGER_RTT_UNCACHED_OFF + #if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #error "SEGGER_RTT_UNCACHED_OFF must be defined when setting SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #else + #define SEGGER_RTT_UNCACHED_OFF (0) + #endif +#endif +#if RTT_USE_ASM + #if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #error "RTT_USE_ASM is not available if SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif +#endif + +#ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file +#include +#include + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ + +// +// Determine how much we must pad the control block to make it a multiple of a cache line in size +// Assuming: U8 = 1B +// U16 = 2B +// U32 = 4B +// U8/U16/U32* = 4B +// +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE // Avoid division by zero in case we do not have any cache + #define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (((NumBytes + SEGGER_RTT_CPU_CACHE_LINE_SIZE - 1) / SEGGER_RTT_CPU_CACHE_LINE_SIZE) * SEGGER_RTT_CPU_CACHE_LINE_SIZE) +#else + #define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (NumBytes) +#endif +#define SEGGER_RTT__CB_SIZE (16 + 4 + 4 + (SEGGER_RTT_MAX_NUM_UP_BUFFERS * 24) + (SEGGER_RTT_MAX_NUM_DOWN_BUFFERS * 24)) +#define SEGGER_RTT__CB_PADDING (SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(SEGGER_RTT__CB_SIZE) - SEGGER_RTT__CB_SIZE) + +/********************************************************************* +* +* Types +* +********************************************************************** +*/ + +// +// Description for a circular buffer (also called "ring buffer") +// which is used as up-buffer (T->H) +// +typedef struct { + const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" + char* pBuffer; // Pointer to start of buffer + unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. + unsigned WrOff; // Position of next item to be written by either target. + volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host. + unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +} SEGGER_RTT_BUFFER_UP; + +// +// Description for a circular buffer (also called "ring buffer") +// which is used as down-buffer (H->T) +// +typedef struct { + const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" + char* pBuffer; // Pointer to start of buffer + unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. + volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host. + unsigned RdOff; // Position of next item to be read by target (down-buffer). + unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. +} SEGGER_RTT_BUFFER_DOWN; + +// +// RTT control block which describes the number of buffers available +// as well as the configuration for each buffer +// +// +typedef struct { + char acID[16]; // Initialized to "SEGGER RTT" + int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2) + int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2) + SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host + SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target +#if SEGGER_RTT__CB_PADDING + unsigned char aDummy[SEGGER_RTT__CB_PADDING]; +#endif +} SEGGER_RTT_CB; + +/********************************************************************* +* +* Global data +* +********************************************************************** +*/ +extern SEGGER_RTT_CB _SEGGER_RTT; + +/********************************************************************* +* +* RTT API functions +* +********************************************************************** +*/ +#ifdef __cplusplus + extern "C" { +#endif +int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_GetKey (void); +unsigned SEGGER_RTT_HasData (unsigned BufferIndex); +int SEGGER_RTT_HasKey (void); +unsigned SEGGER_RTT_HasDataUp (unsigned BufferIndex); +void SEGGER_RTT_Init (void); +unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize); +unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize); +int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName); +int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName); +int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags); +int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags); +int SEGGER_RTT_WaitKey (void); +unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_ASM_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s); +void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_PutChar (unsigned BufferIndex, char c); +unsigned SEGGER_RTT_PutCharSkip (unsigned BufferIndex, char c); +unsigned SEGGER_RTT_PutCharSkipNoLock (unsigned BufferIndex, char c); +unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex); +unsigned SEGGER_RTT_GetBytesInBuffer (unsigned BufferIndex); +// +// Function macro for performance optimization +// +#define SEGGER_RTT_HASDATA(n) (((SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff) + +#if RTT_USE_ASM + #define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock +#endif + +/********************************************************************* +* +* RTT transfer functions to send RTT data via other channels. +* +********************************************************************** +*/ +unsigned SEGGER_RTT_ReadUpBuffer (unsigned BufferIndex, void* pBuffer, unsigned BufferSize); +unsigned SEGGER_RTT_ReadUpBufferNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize); +unsigned SEGGER_RTT_WriteDownBuffer (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteDownBufferNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); + +#define SEGGER_RTT_HASDATA_UP(n) (((SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff) // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + +/********************************************************************* +* +* RTT "Terminal" API functions +* +********************************************************************** +*/ +int SEGGER_RTT_SetTerminal (unsigned char TerminalId); +int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s); + +/********************************************************************* +* +* RTT printf functions (require SEGGER_RTT_printf.c) +* +********************************************************************** +*/ +int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...); +int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList); + +#ifdef __cplusplus + } +#endif + +#endif // ifndef(SEGGER_RTT_ASM) + +/********************************************************************* +* +* Defines +* +********************************************************************** +*/ + +// +// Operating modes. Define behavior if buffer is full (not enough space for entire message) +// +#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default) +#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits. +#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer. +#define SEGGER_RTT_MODE_MASK (3) + +// +// Control sequences, based on ANSI. +// Can be used to control color, and clear the screen +// +#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors +#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left + +#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m" +#define RTT_CTRL_TEXT_RED "\x1B[2;31m" +#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m" +#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m" +#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m" +#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m" +#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m" +#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m" + +#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m" +#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m" +#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m" +#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m" +#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m" +#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m" +#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m" +#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m" + +#define RTT_CTRL_BG_BLACK "\x1B[24;40m" +#define RTT_CTRL_BG_RED "\x1B[24;41m" +#define RTT_CTRL_BG_GREEN "\x1B[24;42m" +#define RTT_CTRL_BG_YELLOW "\x1B[24;43m" +#define RTT_CTRL_BG_BLUE "\x1B[24;44m" +#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m" +#define RTT_CTRL_BG_CYAN "\x1B[24;46m" +#define RTT_CTRL_BG_WHITE "\x1B[24;47m" + +#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m" +#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m" +#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m" +#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m" +#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m" +#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m" +#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m" +#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m" + + +#endif + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_RTT_ASM_ARMv7M.S b/bsp/projects/common/segger/SEGGER_RTT_ASM_ARMv7M.S new file mode 100644 index 0000000..e3579db --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_RTT_ASM_ARMv7M.S @@ -0,0 +1,242 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** + +-------------------------- END-OF-HEADER ----------------------------- + +File : SEGGER_RTT_ASM_ARMv7M.S +Purpose : Assembler implementation of RTT functions for ARMv7M + +Additional information: + This module is written to be assembler-independent and works with + GCC and clang (Embedded Studio) and IAR. +*/ + +#define SEGGER_RTT_ASM // Used to control processed input from header file +#include "SEGGER_RTT.h" + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ + +#define _CCIAR 0 +#define _CCCLANG 1 + +#if (defined __SES_ARM) || (defined __GNUC__) || (defined __clang__) + #define _CC_TYPE _CCCLANG + #define _PUB_SYM .global + #define _EXT_SYM .extern + #define _END .end + #define _WEAK .weak + #define _THUMB_FUNC .thumb_func + #define _THUMB_CODE .code 16 + #define _WORD .word + #define _SECTION(Sect, Type, AlignExp) .section Sect ##, "ax" + #define _ALIGN(Exp) .align Exp + #define _PLACE_LITS .ltorg + #define _DATA_SECT_START + #define _C_STARTUP _start + #define _STACK_END __stack_end__ + #define _RAMFUNC + // + // .text => Link to flash + // .fast => Link to RAM + // OtherSect => Usually link to RAM + // Alignment is 2^x + // +#elif defined (__IASMARM__) + #define _CC_TYPE _CCIAR + #define _PUB_SYM PUBLIC + #define _EXT_SYM EXTERN + #define _END END + #define _WEAK _WEAK + #define _THUMB_FUNC + #define _THUMB_CODE THUMB + #define _WORD DCD + #define _SECTION(Sect, Type, AlignExp) SECTION Sect ## : ## Type ## :REORDER:NOROOT ## (AlignExp) + #define _ALIGN(Exp) alignrom Exp + #define _PLACE_LITS + #define _DATA_SECT_START DATA + #define _C_STARTUP __iar_program_start + #define _STACK_END sfe(CSTACK) + #define _RAMFUNC SECTION_TYPE SHT_PROGBITS, SHF_WRITE | SHF_EXECINSTR + // + // .text => Link to flash + // .textrw => Link to RAM + // OtherSect => Usually link to RAM + // NOROOT => Allows linker to throw away the function, if not referenced + // Alignment is 2^x + // +#endif + +#if (_CC_TYPE == _CCIAR) + NAME SEGGER_RTT_ASM_ARMv7M +#else + .syntax unified +#endif + +#if defined (RTT_USE_ASM) && (RTT_USE_ASM == 1) + #define SHT_PROGBITS 0x1 + +/********************************************************************* +* +* Public / external symbols +* +********************************************************************** +*/ + + _EXT_SYM __aeabi_memcpy + _EXT_SYM __aeabi_memcpy4 + _EXT_SYM _SEGGER_RTT + + _PUB_SYM SEGGER_RTT_ASM_WriteSkipNoLock + +/********************************************************************* +* +* SEGGER_RTT_WriteSkipNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* SEGGER_RTT_WriteSkipNoLock does not lock the application and +* skips all data, if the data does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* MUST be > 0!!! +* This is done for performance reasons, so no initial check has do be done. +* +* Return value +* 1: Data has been copied +* 0: No space, data has not been copied +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, all data is dropped. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ + _SECTION(.text, CODE, 2) + _ALIGN(2) + _THUMB_FUNC +SEGGER_RTT_ASM_WriteSkipNoLock: // unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pData, unsigned NumBytes) { + // + // Cases: + // 1) RdOff <= WrOff => Space until wrap-around is sufficient + // 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks) + // 3) RdOff < WrOff => No space in buf + // 4) RdOff > WrOff => Space is sufficient + // 5) RdOff > WrOff => No space in buf + // + // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough + // + // Register usage: + // R0 Temporary needed as RdOff, register later on + // R1 pData + // R2 + // R3 register. Hold free for subroutine calls + // R4 + // R5 pRing->pBuffer + // R6 pRing (Points to active struct SEGGER_RTT_BUFFER_DOWN) + // R7 WrOff + // + PUSH {R4-R7} + ADD R3,R0,R0, LSL #+1 + LDR.W R0,=_SEGGER_RTT // pRing = &_SEGGER_RTT.aUp[BufferIndex]; + ADD R0,R0,R3, LSL #+3 + ADD R6,R0,#+24 + LDR R0,[R6, #+16] // RdOff = pRing->RdOff; + LDR R7,[R6, #+12] // WrOff = pRing->WrOff; + LDR R5,[R6, #+4] // pRing->pBuffer + CMP R7,R0 + BCC.N _CheckCase4 // if (RdOff <= WrOff) { => Case 1), 2) or 3) + // + // Handling for case 1, later on identical to case 4 + // + LDR R3,[R6, #+8] // Avail = pRing->SizeOfBuffer - WrOff - 1u; => Space until wrap-around (assume 1 byte not usable for case that RdOff == 0) + SUBS R4,R3,R7 // (Used in case we jump into case 2 afterwards) + SUBS R3,R4,#+1 // + CMP R3,R2 + BCC.N _CheckCase2 // if (Avail >= NumBytes) { => Case 1)? +_Case4: + ADDS R5,R7,R5 // pBuffer += WrOff + ADDS R0,R2,R7 // v = WrOff + NumBytes + // + // 2x unrolling for the copy loop that is used most of the time + // This is a special optimization for small SystemView packets and makes them even faster + // + _ALIGN(2) +_LoopCopyStraight: // memcpy(pRing->pBuffer + WrOff, pData, NumBytes); + LDRB R3,[R1], #+1 + STRB R3,[R5], #+1 // *pDest++ = *pSrc++ + SUBS R2,R2,#+1 + BEQ _CSDone + LDRB R3,[R1], #+1 + STRB R3,[R5], #+1 // *pDest++ = *pSrc++ + SUBS R2,R2,#+1 + BNE _LoopCopyStraight +_CSDone: +#if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here + DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the in the struct +#endif + STR R0,[R6, #+12] // pRing->WrOff = WrOff + NumBytes; + MOVS R0,#+1 + POP {R4-R7} + BX LR // Return 1 +_CheckCase2: + ADDS R0,R0,R3 // Avail += RdOff; => Space incl. wrap-around + CMP R0,R2 + BCC.N _Case3 // if (Avail >= NumBytes) { => Case 2? => If not, we have case 3) (does not fit) + // + // Handling for case 2 + // + ADDS R0,R7,R5 // v = pRing->pBuffer + WrOff => Do not change pRing->pBuffer here because 2nd chunk needs org. value + SUBS R2,R2,R4 // NumBytes -= Rem; (Rem = pRing->SizeOfBuffer - WrOff; => Space until end of buffer) +_LoopCopyBeforeWrapAround: // memcpy(pRing->pBuffer + WrOff, pData, Rem); => Copy 1st chunk + LDRB R3,[R1], #+1 + STRB R3,[R0], #+1 // *pDest++ = *pSrc++ + SUBS R4,R4,#+1 + BNE _LoopCopyBeforeWrapAround + // + // Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used + // But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the last element + // In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks + // Therefore, check if 2nd memcpy is necessary at all + // + ADDS R4,R2,#+0 // Save (needed as counter in loop but must be written to after the loop). Also use this inst to update the flags to skip 2nd loop if possible + BEQ.N _No2ChunkNeeded // if (NumBytes) { +_LoopCopyAfterWrapAround: // memcpy(pRing->pBuffer, pData + Rem, NumBytes); + LDRB R3,[R1], #+1 // pData already points to the next src byte due to copy loop increment before this loop + STRB R3,[R5], #+1 // *pDest++ = *pSrc++ + SUBS R2,R2,#+1 + BNE _LoopCopyAfterWrapAround +_No2ChunkNeeded: +#if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here + DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the in the struct +#endif + STR R4,[R6, #+12] // pRing->WrOff = NumBytes; => Must be written after copying data because J-Link may read control block asynchronously while writing into buffer + MOVS R0,#+1 + POP {R4-R7} + BX LR // Return 1 +_CheckCase4: + SUBS R0,R0,R7 + SUBS R0,R0,#+1 // Avail = RdOff - WrOff - 1u; + CMP R0,R2 + BCS.N _Case4 // if (Avail >= NumBytes) { => Case 4) == 1) ? => If not, we have case 5) == 3) (does not fit) +_Case3: + MOVS R0,#+0 + POP {R4-R7} + BX LR // Return 0 + _PLACE_LITS + +#endif // defined (RTT_USE_ASM) && (RTT_USE_ASM == 1) + _END + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_RTT_printf.c b/bsp/projects/common/segger/SEGGER_RTT_printf.c new file mode 100644 index 0000000..8f7ee6c --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_RTT_printf.c @@ -0,0 +1,504 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT_printf.c +Purpose : Replacement for printf to write formatted data via RTT +Revision: $Rev: 17697 $ +---------------------------------------------------------------------- +*/ +#include "SEGGER_RTT.h" +#include "SEGGER_RTT_Conf.h" + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ + +#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE + #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64) +#endif + +#include +#include + + +#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0) +#define FORMAT_FLAG_PAD_ZERO (1u << 1) +#define FORMAT_FLAG_PRINT_SIGN (1u << 2) +#define FORMAT_FLAG_ALTERNATE (1u << 3) + +/********************************************************************* +* +* Types +* +********************************************************************** +*/ + +typedef struct { + char* pBuffer; + unsigned BufferSize; + unsigned Cnt; + + int ReturnValue; + + unsigned RTTBufferIndex; +} SEGGER_RTT_PRINTF_DESC; + +/********************************************************************* +* +* Function prototypes +* +********************************************************************** +*/ + +/********************************************************************* +* +* Static code +* +********************************************************************** +*/ +/********************************************************************* +* +* _StoreChar +*/ +static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) { + unsigned Cnt; + + Cnt = p->Cnt; + if ((Cnt + 1u) <= p->BufferSize) { + *(p->pBuffer + Cnt) = c; + p->Cnt = Cnt + 1u; + p->ReturnValue++; + } + // + // Write part of string, when the buffer is full + // + if (p->Cnt == p->BufferSize) { + if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) { + p->ReturnValue = -1; + } else { + p->Cnt = 0u; + } + } +} + +/********************************************************************* +* +* _PrintUnsigned +*/ +static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { + static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + unsigned Div; + unsigned Digit; + unsigned Number; + unsigned Width; + char c; + + Number = v; + Digit = 1u; + // + // Get actual field width + // + Width = 1u; + while (Number >= Base) { + Number = (Number / Base); + Width++; + } + if (NumDigits > Width) { + Width = NumDigits; + } + // + // Print leading chars if necessary + // + if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) { + if (FieldWidth != 0u) { + if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) { + c = '0'; + } else { + c = ' '; + } + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, c); + if (pBufferDesc->ReturnValue < 0) { + break; + } + } + } + } + if (pBufferDesc->ReturnValue >= 0) { + // + // Compute Digit. + // Loop until Digit has the value of the highest digit required. + // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100. + // + while (1) { + if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned) + NumDigits--; + } else { + Div = v / Digit; + if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done + break; + } + } + Digit *= Base; + } + // + // Output digits + // + do { + Div = v / Digit; + v -= Div * Digit; + _StoreChar(pBufferDesc, _aV2C[Div]); + if (pBufferDesc->ReturnValue < 0) { + break; + } + Digit /= Base; + } while (Digit); + // + // Print trailing spaces if necessary + // + if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, ' '); + if (pBufferDesc->ReturnValue < 0) { + break; + } + } + } + } + } +} + +/********************************************************************* +* +* _PrintInt +*/ +static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { + unsigned Width; + int Number; + + Number = (v < 0) ? -v : v; + + // + // Get actual field width + // + Width = 1u; + while (Number >= (int)Base) { + Number = (Number / (int)Base); + Width++; + } + if (NumDigits > Width) { + Width = NumDigits; + } + if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) { + FieldWidth--; + } + + // + // Print leading spaces if necessary + // + if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, ' '); + if (pBufferDesc->ReturnValue < 0) { + break; + } + } + } + } + // + // Print sign if necessary + // + if (pBufferDesc->ReturnValue >= 0) { + if (v < 0) { + v = -v; + _StoreChar(pBufferDesc, '-'); + } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) { + _StoreChar(pBufferDesc, '+'); + } else { + + } + if (pBufferDesc->ReturnValue >= 0) { + // + // Print leading zeros if necessary + // + if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, '0'); + if (pBufferDesc->ReturnValue < 0) { + break; + } + } + } + } + if (pBufferDesc->ReturnValue >= 0) { + // + // Print number without sign + // + _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags); + } + } + } +} + +/********************************************************************* +* +* Public code +* +********************************************************************** +*/ +/********************************************************************* +* +* SEGGER_RTT_vprintf +* +* Function description +* Stores a formatted string in SEGGER RTT control block. +* This data is read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") +* sFormat Pointer to format string +* pParamList Pointer to the list of arguments for the format string +* +* Return values +* >= 0: Number of bytes which have been stored in the "Up"-buffer. +* < 0: Error +*/ +int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) { + char c; + SEGGER_RTT_PRINTF_DESC BufferDesc; + int v; + unsigned NumDigits; + unsigned FormatFlags; + unsigned FieldWidth; + char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE]; + + BufferDesc.pBuffer = acBuffer; + BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE; + BufferDesc.Cnt = 0u; + BufferDesc.RTTBufferIndex = BufferIndex; + BufferDesc.ReturnValue = 0; + + do { + c = *sFormat; + sFormat++; + if (c == 0u) { + break; + } + if (c == '%') { + // + // Filter out flags + // + FormatFlags = 0u; + v = 1; + do { + c = *sFormat; + switch (c) { + case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break; + case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break; + case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break; + case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break; + default: v = 0; break; + } + } while (v); + // + // filter out field with + // + FieldWidth = 0u; + do { + c = *sFormat; + if ((c < '0') || (c > '9')) { + break; + } + sFormat++; + FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0'); + } while (1); + + // + // Filter out precision (number of digits to display) + // + NumDigits = 0u; + c = *sFormat; + if (c == '.') { + sFormat++; + do { + c = *sFormat; + if ((c < '0') || (c > '9')) { + break; + } + sFormat++; + NumDigits = NumDigits * 10u + ((unsigned)c - '0'); + } while (1); + } + // + // Filter out length modifier + // + c = *sFormat; + do { + if ((c == 'l') || (c == 'h')) { + sFormat++; + c = *sFormat; + } else { + break; + } + } while (1); + // + // Handle specifiers + // + switch (c) { + case 'c': { + char c0; + v = va_arg(*pParamList, int); + c0 = (char)v; + _StoreChar(&BufferDesc, c0); + break; + } + case 'd': + v = va_arg(*pParamList, int); + _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags); + break; + case 'u': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags); + break; + case 'x': + case 'X': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags); + break; + case 's': + { + const char * s = va_arg(*pParamList, const char *); + do { + c = *s; + s++; + if (c == '\0') { + break; + } + _StoreChar(&BufferDesc, c); + } while (BufferDesc.ReturnValue >= 0); + } + break; + case 'p': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u); + break; + case '%': + _StoreChar(&BufferDesc, '%'); + break; + default: + break; + } + sFormat++; + } else { + _StoreChar(&BufferDesc, c); + } + } while (BufferDesc.ReturnValue >= 0); + + if (BufferDesc.ReturnValue > 0) { + // + // Write remaining data, if any + // + if (BufferDesc.Cnt != 0u) { + SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt); + } + BufferDesc.ReturnValue += (int)BufferDesc.Cnt; + } + return BufferDesc.ReturnValue; +} + +/********************************************************************* +* +* SEGGER_RTT_printf +* +* Function description +* Stores a formatted string in SEGGER RTT control block. +* This data is read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") +* sFormat Pointer to format string, followed by the arguments for conversion +* +* Return values +* >= 0: Number of bytes which have been stored in the "Up"-buffer. +* < 0: Error +* +* Notes +* (1) Conversion specifications have following syntax: +* %[flags][FieldWidth][.Precision]ConversionSpecifier +* (2) Supported flags: +* -: Left justify within the field width +* +: Always print sign extension for signed conversions +* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision +* Supported conversion specifiers: +* c: Print the argument as one char +* d: Print the argument as a signed integer +* u: Print the argument as an unsigned integer +* x: Print the argument as an hexadecimal integer +* s: Print the string pointed to by the argument +* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.) +*/ +int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) { + int r; + va_list ParamList; + + va_start(ParamList, sFormat); + r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList); + va_end(ParamList); + return r; +} +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_SYSVIEW.c b/bsp/projects/common/segger/SEGGER_SYSVIEW.c new file mode 100644 index 0000000..3fb1acb --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_SYSVIEW.c @@ -0,0 +1,3102 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +-------------------------- END-OF-HEADER ----------------------------- + +File : SEGGER_SYSVIEW.c +Purpose : System visualization API implementation. +Revision: $Rev: 26232 $ + +Additional information: + Packet format: + Packets with IDs 0..23 are standard packets with known structure. + For efficiency, they do *NOT* contain a length field. + + + Packets with IDs 24..31 are standard packets with extendible + structure and contain a length field. + + + Packet ID 31 is used for SystemView extended events. + + + Packets with IDs >= 32 always contain a length field. + + + Packet IDs: + 0.. 31 : Standard packets, known by SystemView. + 32..1023 : OS-definable packets, described in a SystemView description file. + 1024..2047 : User-definable packets, described in a SystemView description file. + 2048..32767: Undefined. + + Data encoding: + Basic types (int, short, char, ...): + Basic types are encoded little endian with most-significant bit variant + encoding. + Each encoded byte contains 7 data bits [6:0] and the MSB continuation bit. + The continuation bit indicates whether the next byte belongs to the data + (bit set) or this is the last byte (bit clear). + The most significant bits of data are encoded first, proceeding to the + least significant bits in the final byte (little endian). + + Example encoding: + Data: 0x1F4 (500) + Encoded: 0xF4 (First 7 data bits 74 | Continuation bit) + 0x03 (Second 7 data bits 03, no continuation) + + Data: 0xFFFFFFFF + Encoded: 0xFF 0xFF 0xFF 0xFF 0x0F + + Data: 0xA2 (162), 0x03 (3), 0x7000 + Encoded: 0xA2 0x01 0x03 0x80 0xE0 0x01 + + Byte arrays and strings: + Byte arrays and strings are encoded as followed by the raw data. + NumBytes is encoded as a basic type with a theoretical maximum of 4G. + + Example encoding: + Data: "Hello World\0" (0x48 0x65 0x6C 0x6C 0x6F 0x20 0x57 0x6F 0x72 0x6C 0x64 0x00) + Encoded: 0x0B 0x48 0x65 0x6C 0x6C 0x6F 0x20 0x57 0x6F 0x72 0x6C 0x64 + + Examples packets: + 01 F4 03 80 80 10 // Overflow packet. Data is a single U32. + This packet means: 500 packets lost, Timestamp is 0x40000 + + 02 0F 50 // ISR(15) Enter. Timestamp 80 (0x50) + + 03 20 // ISR Exit. Timestamp 32 (0x20) (Shortest possible packet.) + + Sample code for user defined Packets: + #define MY_ID 0x400 // Any value between 0x400 and 0x7FF + void SendMyPacket(unsigned Para0, unsigned Para1, const char* s) { + U8 aPacket[SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + MAX_STR_LEN + 1]; + U8* pPayload; + // + pPayload = SEGGER_SYSVIEW_PPREPARE_PACKET(aPacket); // Prepare the packet for SystemView + pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para0); // Add the first parameter to the packet + pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para1); // Add the second parameter to the packet + pPayload = SEGGER_SYSVIEW_EncodeString(pPayload, s, MAX_STR_LEN); // Add the string to the packet + // + SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, MY_ID); // Send the packet with EventId = MY_ID + } + + #define MY_ID_1 0x401 + void SendOnePara(unsigned Para0) { + SEGGER_SYSVIEW_RecordU32(MY_ID_1, Para0); + } + +*/ + +/********************************************************************* +* +* #include section +* +********************************************************************** +*/ + +#define SEGGER_SYSVIEW_C // For EXTERN statements in SEGGER_SYSVIEW.h + +#include +#include +#include +#include "SEGGER_SYSVIEW_Int.h" +#include "SEGGER_RTT.h" + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ +#if SEGGER_SYSVIEW_ID_SHIFT + #define SHRINK_ID(Id) (((Id) - _SYSVIEW_Globals.RAMBaseAddress) >> SEGGER_SYSVIEW_ID_SHIFT) +#else + #define SHRINK_ID(Id) ((Id) - _SYSVIEW_Globals.RAMBaseAddress) +#endif + +#if SEGGER_SYSVIEW_RTT_CHANNEL > 0 + #define CHANNEL_ID_UP SEGGER_SYSVIEW_RTT_CHANNEL + #define CHANNEL_ID_DOWN SEGGER_SYSVIEW_RTT_CHANNEL +#else + #define CHANNEL_ID_UP _SYSVIEW_Globals.UpChannel + #define CHANNEL_ID_DOWN _SYSVIEW_Globals.DownChannel +#endif + +#if SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE + #if (SEGGER_SYSVIEW_RTT_BUFFER_SIZE % SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE) + #error "SEGGER_SYSVIEW_RTT_BUFFER_SIZE must be a multiple of SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE" + #endif +#endif + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ +// Timestamps may be less than full 32-bits, in which case we need to zero +// the unused bits to properly handle overflows. +// Note that this is a quite common scenario, as a 32-bit time such as +// SysTick might be scaled down to reduce bandwith +// or a 16-bit hardware time might be used. +#if SEGGER_SYSVIEW_TIMESTAMP_BITS < 32 // Eliminate unused bits in case hardware timestamps are less than 32 bits + #define MAKE_DELTA_32BIT(Delta) Delta <<= 32 - SEGGER_SYSVIEW_TIMESTAMP_BITS; \ + Delta >>= 32 - SEGGER_SYSVIEW_TIMESTAMP_BITS; +#else + #define MAKE_DELTA_32BIT(Delta) +#endif + +#if SEGGER_SYSVIEW_SUPPORT_LONG_ID + #define _MAX_ID_BYTES 5u +#else + #define _MAX_ID_BYTES 2u +#endif + +#if SEGGER_SYSVIEW_SUPPORT_LONG_DATA + #define _MAX_DATA_BYTES 5u +#else + #define _MAX_DATA_BYTES 2u +#endif + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ +#define ENABLE_STATE_OFF 0 +#define ENABLE_STATE_ON 1 +#define ENABLE_STATE_DROPPING 2 + +#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0) +#define FORMAT_FLAG_PAD_ZERO (1u << 1) +#define FORMAT_FLAG_PRINT_SIGN (1u << 2) +#define FORMAT_FLAG_ALTERNATE (1u << 3) + +#define MODULE_EVENT_OFFSET (512) + +/********************************************************************* +* +* Types, local +* +********************************************************************** +*/ +typedef struct { + U8* pBuffer; + U8* pPayload; + U8* pPayloadStart; + U32 Options; + unsigned Cnt; +} SEGGER_SYSVIEW_PRINTF_DESC; + +typedef struct { + U8 EnableState; // 0: Disabled, 1: Enabled, (2: Dropping) + U8 UpChannel; + U8 RecursionCnt; + U32 SysFreq; + U32 CPUFreq; + U32 LastTxTimeStamp; + U32 RAMBaseAddress; +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) + U32 PacketCount; +#else + U32 DropCount; + U8 DownChannel; +#endif + U32 DisabledEvents; + const SEGGER_SYSVIEW_OS_API* pOSAPI; + SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC* pfSendSysDesc; +} SEGGER_SYSVIEW_GLOBALS; + +/********************************************************************* +* +* Function prototypes, required +* +********************************************************************** +*/ +static void _SendPacket(U8* pStartPacket, U8* pEndPacket, unsigned int EventId); + +/********************************************************************* +* +* Static data +* +********************************************************************** +*/ +static const U8 _abSync[10] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +#if SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE + #ifdef SEGGER_SYSVIEW_SECTION + // + // Alignment + special section required + // + #if (defined __GNUC__) + __attribute__ ((section (SEGGER_SYSVIEW_SECTION), aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE))) static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + __attribute__ ((section (SEGGER_SYSVIEW_SECTION), aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE))) static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #elif (defined __ICCARM__) || (defined __ICCRX__) + #pragma location=SEGGER_SYSVIEW_SECTION + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + #pragma location=SEGGER_SYSVIEW_SECTION + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #elif (defined __CC_ARM) + __attribute__ ((section (SEGGER_SYSVIEW_SECTION), aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE), zero_init)) static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + __attribute__ ((section (SEGGER_SYSVIEW_SECTION), aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE), zero_init)) static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #else + #error "Do not know how to place SystemView buffers in specific section" + #endif + #else + // + // Only alignment required + // + #if (defined __GNUC__) + __attribute__ ((aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE))) static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + __attribute__ ((aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE))) static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #elif (defined __ICCARM__) || (defined __ICCRX__) + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #elif (defined __CC_ARM) + __attribute__ ((aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE), zero_init)) static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + __attribute__ ((aligned (SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE), zero_init)) static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #else + #error "Do not know how to align SystemView buffers to cache line size" + #endif + #endif +#else + #ifdef SEGGER_SYSVIEW_SECTION + // + // Only special section required + // + #if (defined __GNUC__) + __attribute__ ((section (SEGGER_SYSVIEW_SECTION))) static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + __attribute__ ((section (SEGGER_SYSVIEW_SECTION))) static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #elif (defined __ICCARM__) || (defined __ICCRX__) + #pragma location=SEGGER_SYSVIEW_SECTION + static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + #pragma location=SEGGER_SYSVIEW_SECTION + static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #elif (defined __CC_ARM) + __attribute__ ((section (SEGGER_SYSVIEW_SECTION), zero_init)) static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + __attribute__ ((section (SEGGER_SYSVIEW_SECTION), zero_init)) static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #else + #error "Do not know how to place SystemView buffers in specific section" + #endif + #else + // + // Neither special section nor alignment required + // + static char _UpBuffer [SEGGER_SYSVIEW_RTT_BUFFER_SIZE]; + #if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + static char _DownBuffer[8]; // Small, fixed-size buffer, for back-channel comms + #endif + #endif +#endif + +static SEGGER_SYSVIEW_GLOBALS _SYSVIEW_Globals; + +static SEGGER_SYSVIEW_MODULE* _pFirstModule; +static U8 _NumModules; + +/********************************************************************* +* +* Static code +* +********************************************************************** +*/ + +#define ENCODE_U32(pDest, Value) { \ + U8* pSysviewPointer; \ + U32 SysViewData; \ + pSysviewPointer = pDest; \ + SysViewData = Value; \ + while(SysViewData > 0x7F) { \ + *pSysviewPointer++ = (U8)(SysViewData | 0x80); \ + SysViewData >>= 7; \ + }; \ + *pSysviewPointer++ = (U8)SysViewData; \ + pDest = pSysviewPointer; \ + }; + + + +#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 1) +static U8 _aPacket[SEGGER_SYSVIEW_MAX_PACKET_SIZE]; + +#define RECORD_START(PacketSize) SEGGER_SYSVIEW_LOCK(); \ + pPayloadStart = _PreparePacket(_aPacket); + +#define RECORD_END() SEGGER_SYSVIEW_UNLOCK() + +#else + +#define RECORD_START(PacketSize) U8 aPacket[(PacketSize)]; \ + pPayloadStart = _PreparePacket(aPacket); \ + +#define RECORD_END() + +#endif + +/********************************************************************* +* +* _EncodeData() +* +* Function description +* Encode a byte buffer in variable-length format. +* +* Parameters +* pPayload - Pointer to where string will be encoded. +* pSrc - Pointer to data buffer to be encoded. +* NumBytes - Number of bytes in the buffer to be encoded. +* +* Return value +* Pointer to the byte following the value, i.e. the first free +* byte in the payload and the next position to store payload +* content. +* +* Additional information +* The data is encoded as a count byte followed by the contents +* of the data buffer. +* Make sure NumBytes + 1 bytes are free for the payload. +*/ +static U8* _EncodeData(U8* pPayload, const char* pSrc, unsigned int NumBytes) { + unsigned int n; + const U8* p; + // + n = 0; + p = (const U8*)pSrc; + // + // Write Len + // + if (NumBytes < 255) { + *pPayload++ = (U8)NumBytes; + } else { + *pPayload++ = 255; + *pPayload++ = (NumBytes & 255); + *pPayload++ = ((NumBytes >> 8) & 255); + } + while (n < NumBytes) { + *pPayload++ = *p++; + n++; + } + return pPayload; +} + +/********************************************************************* +* +* _EncodeStr() +* +* Function description +* Encode a string in variable-length format. +* +* Parameters +* pPayload - Pointer to where string will be encoded. +* pText - String to encode. +* Limit - Maximum number of characters to encode from string. +* +* Return value +* Pointer to the byte following the value, i.e. the first free +* byte in the payload and the next position to store payload +* content. +* +* Additional information +* The string is encoded as a count byte followed by the contents +* of the string. +* No more than 1 + Limit bytes will be encoded to the payload. +*/ +static U8 *_EncodeStr(U8 *pPayload, const char *pText, unsigned int Limit) { + unsigned int n; + unsigned int Len; + // + // Compute string len + // + Len = 0; + if (pText != NULL) { + while(*(pText + Len) != 0) { + Len++; + } + if (Len > Limit) { + Len = Limit; + } + } + // + // Write Len + // + if (Len < 255) { + *pPayload++ = (U8)Len; + } else { + *pPayload++ = 255; + *pPayload++ = (Len & 255); + *pPayload++ = ((Len >> 8) & 255); + } + // + // copy string + // + n = 0; + while (n < Len) { + *pPayload++ = *pText++; + n++; + } + return pPayload; +} + +/********************************************************************* +* +* _PreparePacket() +* +* Function description +* Prepare a SystemView event packet header. +* +* Parameters +* pPacket - Pointer to start of packet to initialize. +* +* Return value +* Pointer to first byte of packet payload. +* +* Additional information +* The payload length and evnetId are not initialized. +* PreparePacket only reserves space for them and they are +* computed and filled in by the sending function. +*/ +static U8* _PreparePacket(U8* pPacket) { + return pPacket + _MAX_ID_BYTES + _MAX_DATA_BYTES; +} + +/********************************************************************* +* +* _HandleIncomingPacket() +* +* Function description +* Read an incoming command from the down channel and process it. +* +* Additional information +* This function is called each time after sending a packet. +* Processing incoming packets is done asynchronous. SystemView might +* already have sent event packets after the host has sent a command. +*/ +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) +static void _HandleIncomingPacket(void) { + U8 Cmd; + unsigned int Status; + // + Status = SEGGER_RTT_ReadNoLock(CHANNEL_ID_DOWN, &Cmd, 1); + if (Status > 0) { + switch (Cmd) { + case SEGGER_SYSVIEW_COMMAND_ID_START: + SEGGER_SYSVIEW_Start(); + break; + case SEGGER_SYSVIEW_COMMAND_ID_STOP: + SEGGER_SYSVIEW_Stop(); + break; + case SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME: + SEGGER_SYSVIEW_RecordSystime(); + break; + case SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST: + SEGGER_SYSVIEW_SendTaskList(); + break; + case SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC: + SEGGER_SYSVIEW_GetSysDesc(); + break; + case SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES: + SEGGER_SYSVIEW_SendNumModules(); + break; + case SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC: + SEGGER_SYSVIEW_SendModuleDescription(); + break; + case SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE: + Status = SEGGER_RTT_ReadNoLock(CHANNEL_ID_DOWN, &Cmd, 1); + if (Status > 0) { + SEGGER_SYSVIEW_SendModule(Cmd); + } + break; + case SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT: + break; + default: + if (Cmd >= 128) { // Unknown extended command. Dummy read its parameter. + SEGGER_RTT_ReadNoLock(CHANNEL_ID_DOWN, &Cmd, 1); + } + break; + } + } +} +#endif // (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + +/********************************************************************* +* +* _TrySendOverflowPacket() +* +* Function description +* Try to transmit an SystemView Overflow packet containing the +* number of dropped packets. +* +* Additional information +* Format as follows: +* 01 Max. packet len is 1 + 5 + 5 = 11 +* +* Example packets sent +* 01 20 40 +* +* Return value +* !=0: Success, Message sent (stored in RTT-Buffer) +* ==0: Buffer full, Message *NOT* stored +* +*/ +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) +static int _TrySendOverflowPacket(void) { + U32 TimeStamp; + I32 Delta; + int Status; + U8 aPacket[11]; + U8* pPayload; + + aPacket[0] = SYSVIEW_EVTID_OVERFLOW; // 1 + pPayload = &aPacket[1]; + ENCODE_U32(pPayload, _SYSVIEW_Globals.DropCount); + // + // Compute time stamp delta and append it to packet. + // + TimeStamp = SEGGER_SYSVIEW_GET_TIMESTAMP(); + Delta = TimeStamp - _SYSVIEW_Globals.LastTxTimeStamp; + MAKE_DELTA_32BIT(Delta); + ENCODE_U32(pPayload, Delta); + // + // Try to store packet in RTT buffer and update time stamp when this was successful + // + Status = (int)SEGGER_RTT_WriteSkipNoLock(CHANNEL_ID_UP, aPacket, (unsigned int)(pPayload - aPacket)); + SEGGER_SYSVIEW_ON_EVENT_RECORDED(pPayload - aPacket); + if (Status) { + _SYSVIEW_Globals.LastTxTimeStamp = TimeStamp; + _SYSVIEW_Globals.EnableState--; // EnableState has been 2, will be 1. Always. + } else { + _SYSVIEW_Globals.DropCount++; + } + // + return Status; +} +#endif // (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + +/********************************************************************* +* +* _SendSyncInfo() +* +* Function description +* Send SystemView sync packet and system information in +* post mortem mode. +* +* Additional information +* Sync is 10 * 0x00 without timestamp +*/ +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) +static void _SendSyncInfo(void) { + // + // Add sync packet ( 10 * 0x00) + // Send system description + // Send system time + // Send task list + // Send module description + // Send module information + // + SEGGER_RTT_WriteWithOverwriteNoLock(CHANNEL_ID_UP, _abSync, 10); + SEGGER_SYSVIEW_ON_EVENT_RECORDED(10); + SEGGER_SYSVIEW_RecordVoid(SYSVIEW_EVTID_TRACE_START); + { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, _SYSVIEW_Globals.SysFreq); + ENCODE_U32(pPayload, _SYSVIEW_Globals.CPUFreq); + ENCODE_U32(pPayload, _SYSVIEW_Globals.RAMBaseAddress); + ENCODE_U32(pPayload, SEGGER_SYSVIEW_ID_SHIFT); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_INIT); + RECORD_END(); + } + if (_SYSVIEW_Globals.pfSendSysDesc) { + _SYSVIEW_Globals.pfSendSysDesc(); + } + SEGGER_SYSVIEW_RecordSystime(); + SEGGER_SYSVIEW_SendTaskList(); + if (_NumModules > 0) { + int n; + SEGGER_SYSVIEW_SendNumModules(); + for (n = 0; n < _NumModules; n++) { + SEGGER_SYSVIEW_SendModule(n); + } + SEGGER_SYSVIEW_SendModuleDescription(); + } +} +#endif // (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) + +/********************************************************************* +* +* _SendPacket() +* +* Function description +* Send a SystemView packet over RTT. RTT channel and mode are +* configured by macros when the SystemView component is initialized. +* This function takes care of maintaining the packet drop count +* and sending overflow packets when necessary. +* The packet must be passed without Id and Length because this +* function prepends it to the packet before transmission. +* +* Parameters +* pStartPacket - Pointer to start of packet payload. +* There must be at least 4 bytes free to prepend Id and Length. +* pEndPacket - Pointer to end of packet payload. +* EventId - Id of the event to send. +* +*/ +static void _SendPacket(U8* pStartPacket, U8* pEndPacket, unsigned int EventId) { + unsigned int NumBytes; + U32 TimeStamp; + U32 Delta; +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + unsigned int Status; +#endif + +#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0) + SEGGER_SYSVIEW_LOCK(); +#endif + +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) + if (_SYSVIEW_Globals.EnableState == 0) { + goto SendDone; + } +#else + if (_SYSVIEW_Globals.EnableState == 1) { // Enabled, no dropped packets remaining + goto Send; + } + if (_SYSVIEW_Globals.EnableState == 0) { + goto SendDone; + } + // + // Handle buffer full situations: + // Have packets been dropped before because buffer was full? + // In this case try to send and overflow packet. + // + if (_SYSVIEW_Globals.EnableState == 2) { + _TrySendOverflowPacket(); + if (_SYSVIEW_Globals.EnableState != 1) { + goto SendDone; + } + } +Send: +#endif + // + // Check if event is disabled from being recorded. + // + if (EventId < 32) { + if (_SYSVIEW_Globals.DisabledEvents & ((U32)1u << EventId)) { + goto SendDone; + } + } + // + // Prepare actual packet. + // If it is a known packet, prepend eventId only, + // otherwise prepend packet length and eventId. + // + if (EventId < 24) { + *--pStartPacket = (U8)EventId; + } else { + // + // Get data length and prepend it. + // + NumBytes = (unsigned int)(pEndPacket - pStartPacket); +#if SEGGER_SYSVIEW_SUPPORT_LONG_DATA + if (NumBytes < 127) { + *--pStartPacket = EventId; + } else { + // + // Backwards U32 encode EventId. + // + if (NumBytes < (1u << 14)) { // Encodes in 2 bytes + *--pStartPacket = (U8)(NumBytes >> 7); + *--pStartPacket = (U8)(NumBytes | 0x80); + } else if (NumBytes < (1u << 21)) { // Encodes in 3 bytes + *--pStartPacket = (U8)(NumBytes >> 14); + *--pStartPacket = (U8)((NumBytes >> 7) | 0x80); + *--pStartPacket = (U8)(NumBytes | 0x80); + } else if (NumBytes < (1u << 28)) { // Encodes in 4 bytes + *--pStartPacket = (U8)(NumBytes >> 21); + *--pStartPacket = (U8)((NumBytes >> 14) | 0x80); + *--pStartPacket = (U8)((NumBytes >> 7) | 0x80); + *--pStartPacket = (U8)(NumBytes | 0x80); + } else { // Encodes in 5 bytes + *--pStartPacket = (U8)(NumBytes >> 28); + *--pStartPacket = (U8)((NumBytes >> 21) | 0x80); + *--pStartPacket = (U8)((NumBytes >> 14) | 0x80); + *--pStartPacket = (U8)((NumBytes >> 7) | 0x80); + *--pStartPacket = (U8)(NumBytes | 0x80); + } + } +#else + if (NumBytes > 127) { + *--pStartPacket = (U8)(NumBytes >> 7); + *--pStartPacket = (U8)(NumBytes | 0x80); + } else { + *--pStartPacket = (U8)NumBytes; + } +#endif + // + // Prepend EventId. + // +#if SEGGER_SYSVIEW_SUPPORT_LONG_ID + if (EventId < 127) { + *--pStartPacket = (U8)EventId; + } else { + // + // Backwards U32 encode EventId. + // + if (EventId < (1u << 14)) { // Encodes in 2 bytes + *--pStartPacket = (U8)(EventId >> 7); + *--pStartPacket = (U8)(EventId | 0x80); + } else if (EventId < (1u << 21)) { // Encodes in 3 bytes + *--pStartPacket = (U8)(EventId >> 14); + *--pStartPacket = (U8)((EventId >> 7) | 0x80); + *--pStartPacket = (U8)(EventId | 0x80); + } else if (EventId < (1u << 28)) { // Encodes in 4 bytes + *--pStartPacket = (U8)(EventId >> 21); + *--pStartPacket = (U8)((EventId >> 14) | 0x80); + *--pStartPacket = (U8)((EventId >> 7) | 0x80); + *--pStartPacket = (U8)(EventId | 0x80); + } else { // Encodes in 5 bytes + *--pStartPacket = (U8)(EventId >> 28); + *--pStartPacket = (U8)((EventId >> 21) | 0x80); + *--pStartPacket = (U8)((EventId >> 14) | 0x80); + *--pStartPacket = (U8)((EventId >> 7) | 0x80); + *--pStartPacket = (U8)(EventId | 0x80); + } + } +#else + if (EventId > 127) { + *--pStartPacket = (U8)(EventId >> 7); + *--pStartPacket = (U8)(EventId | 0x80); + } else { + *--pStartPacket = (U8)EventId; + } +#endif + } + // + // Compute time stamp delta and append it to packet. + // + TimeStamp = SEGGER_SYSVIEW_GET_TIMESTAMP(); + Delta = TimeStamp - _SYSVIEW_Globals.LastTxTimeStamp; + MAKE_DELTA_32BIT(Delta); + ENCODE_U32(pEndPacket, Delta); +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) + // + // Store packet in RTT buffer by overwriting old data and update time stamp + // + SEGGER_RTT_WriteWithOverwriteNoLock(CHANNEL_ID_UP, pStartPacket, pEndPacket - pStartPacket); + SEGGER_SYSVIEW_ON_EVENT_RECORDED(pEndPacket - pStartPacket); + _SYSVIEW_Globals.LastTxTimeStamp = TimeStamp; +#else + // + // Try to store packet in RTT buffer and update time stamp when this was successful + // + Status = SEGGER_RTT_WriteSkipNoLock(CHANNEL_ID_UP, pStartPacket, (unsigned int)(pEndPacket - pStartPacket)); + SEGGER_SYSVIEW_ON_EVENT_RECORDED(pEndPacket - pStartPacket); + if (Status) { + _SYSVIEW_Globals.LastTxTimeStamp = TimeStamp; + } else { + _SYSVIEW_Globals.EnableState++; // EnableState has been 1, will be 2. Always. + } +#endif + +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) + // + // Add sync and system information periodically if we are in post mortem mode + // + if (_SYSVIEW_Globals.RecursionCnt == 0) { // Avoid uncontrolled nesting. This way, this routine can call itself once, but no more often than that. + _SYSVIEW_Globals.RecursionCnt = 1; + if (_SYSVIEW_Globals.PacketCount++ & (1 << SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT)) { + _SendSyncInfo(); + _SYSVIEW_Globals.PacketCount = 0; + } + _SYSVIEW_Globals.RecursionCnt = 0; + } +SendDone: + ; // Avoid "label at end of compound statement" error when using static buffer +#else +SendDone: + // + // Check if host is sending data which needs to be processed. + // Note that since this code is called for every packet, it is very time critical, so we do + // only what is really needed here, which is checking if there is any data + // + if (SEGGER_RTT_HASDATA(CHANNEL_ID_DOWN)) { + if (_SYSVIEW_Globals.RecursionCnt == 0) { // Avoid uncontrolled nesting. This way, this routine can call itself once, but no more often than that. + _SYSVIEW_Globals.RecursionCnt = 1; + _HandleIncomingPacket(); + _SYSVIEW_Globals.RecursionCnt = 0; + } + } +#endif + // +#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0) + SEGGER_SYSVIEW_UNLOCK(); // We are done. Unlock and return +#endif +} + +#ifndef SEGGER_SYSVIEW_EXCLUDE_PRINTF // Define in project to avoid warnings about variable parameter list +/********************************************************************* +* +* _VPrintHost() +* +* Function description +* Send a format string and its parameters to the host. +* +* Parameters +* s Pointer to format string. +* Options Options to be sent to the host. +* pParamList Pointer to the list of arguments for the format string. +*/ +static int _VPrintHost(const char* s, U32 Options, va_list* pParamList) { + U32 aParas[SEGGER_SYSVIEW_MAX_ARGUMENTS]; + U32* pParas; + U32 NumArguments; + const char* p; + char c; + U8* pPayload; + U8* pPayloadStart; +#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT + U8 HasNonScalar; + + HasNonScalar = 0; +#endif + // + // Count number of arguments by counting '%' characters in string. + // If enabled, check for non-scalar modifier flags to format string on the target. + // + p = s; + NumArguments = 0; + for (;;) { + c = *p++; + if (c == 0) { + break; + } + if (c == '%') { + c = *p; +#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT == 0 + aParas[NumArguments++] = (U32)(va_arg(*pParamList, int)); + if (NumArguments == SEGGER_SYSVIEW_MAX_ARGUMENTS) { + break; + } +#else + if (c == 's') { + HasNonScalar = 1; + break; + } else { + aParas[NumArguments++] = (U32)(va_arg(*pParamList, int)); + if (NumArguments == SEGGER_SYSVIEW_MAX_ARGUMENTS) { + break; + } + } +#endif + } + } + +#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT + if (HasNonScalar) { + return -1; + } +#endif + // + // Send string and parameters to host + // + { + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_MAX_STRING_LEN + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_ARGUMENTS * SEGGER_SYSVIEW_QUANTA_U32); + pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN); + ENCODE_U32(pPayload, Options); + ENCODE_U32(pPayload, NumArguments); + pParas = aParas; + while (NumArguments--) { + ENCODE_U32(pPayload, (*pParas)); + pParas++; + } + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED); + RECORD_END(); + } + return 0; +} + +/********************************************************************* +* +* _StoreChar() +* +* Function description +* Stores a character in the printf-buffer and sends the buffer when +* it is filled. +* +* Parameters +* p Pointer to the buffer description. +* c Character to be printed. +*/ +static void _StoreChar(SEGGER_SYSVIEW_PRINTF_DESC * p, char c) { + unsigned int Cnt; + U8* pPayload; + U32 Options; + + Cnt = p->Cnt; + if ((Cnt + 1u) <= SEGGER_SYSVIEW_MAX_STRING_LEN) { + *(p->pPayload++) = (U8)c; + p->Cnt = Cnt + 1u; + } + // + // Write part of string, when the buffer is full + // + if (p->Cnt == SEGGER_SYSVIEW_MAX_STRING_LEN) { + *(p->pPayloadStart) = (U8)p->Cnt; + pPayload = p->pPayload; + Options = p->Options; + ENCODE_U32(pPayload, Options); + ENCODE_U32(pPayload, 0); + _SendPacket(p->pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED); + p->pPayloadStart = _PreparePacket(p->pBuffer); + p->pPayload = p->pPayloadStart + 1u; + p->Cnt = 0u; + } +} + +/********************************************************************* +* +* _PrintUnsigned() +* +* Function description +* Print an unsigned integer with the given formatting into the +* formatted string. +* +* Parameters +* pBufferDesc Pointer to the buffer description. +* v Value to be printed. +* Base Base of the value. +* NumDigits Number of digits to be printed. +* FieldWidth Width of the printed field. +* FormatFlags Flags for formatting the value. +*/ +static void _PrintUnsigned(SEGGER_SYSVIEW_PRINTF_DESC * pBufferDesc, unsigned int v, unsigned int Base, unsigned int NumDigits, unsigned int FieldWidth, unsigned int FormatFlags) { + static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + unsigned int Div; + unsigned int Digit; + unsigned int Number; + unsigned int Width; + char c; + + Number = v; + Digit = 1u; + // + // Get actual field width + // + Width = 1u; + while (Number >= Base) { + Number = (Number / Base); + Width++; + } + if (NumDigits > Width) { + Width = NumDigits; + } + // + // Print leading chars if necessary + // + if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) { + if (FieldWidth != 0u) { + if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) { + c = '0'; + } else { + c = ' '; + } + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, c); + } + } + } + // + // Compute Digit. + // Loop until Digit has the value of the highest digit required. + // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100. + // + while (1) { + if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned) + NumDigits--; + } else { + Div = v / Digit; + if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done + break; + } + } + Digit *= Base; + } + // + // Output digits + // + do { + Div = v / Digit; + v -= Div * Digit; + _StoreChar(pBufferDesc, _aV2C[Div]); + Digit /= Base; + } while (Digit); + // + // Print trailing spaces if necessary + // + if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, ' '); + } + } + } +} + +/********************************************************************* +* +* _PrintInt() +* +* Function description +* Print a signed integer with the given formatting into the +* formatted string. +* +* Parameters +* pBufferDesc Pointer to the buffer description. +* v Value to be printed. +* Base Base of the value. +* NumDigits Number of digits to be printed. +* FieldWidth Width of the printed field. +* FormatFlags Flags for formatting the value. +*/ +static void _PrintInt(SEGGER_SYSVIEW_PRINTF_DESC * pBufferDesc, int v, unsigned int Base, unsigned int NumDigits, unsigned int FieldWidth, unsigned int FormatFlags) { + unsigned int Width; + int Number; + + Number = (v < 0) ? -v : v; + + // + // Get actual field width + // + Width = 1u; + while (Number >= (int)Base) { + Number = (Number / (int)Base); + Width++; + } + if (NumDigits > Width) { + Width = NumDigits; + } + if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) { + FieldWidth--; + } + + // + // Print leading spaces if necessary + // + if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, ' '); + } + } + } + // + // Print sign if necessary + // + if (v < 0) { + v = -v; + _StoreChar(pBufferDesc, '-'); + } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) { + _StoreChar(pBufferDesc, '+'); + } else { + + } + // + // Print leading zeros if necessary + // + if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) { + if (FieldWidth != 0u) { + while ((FieldWidth != 0u) && (Width < FieldWidth)) { + FieldWidth--; + _StoreChar(pBufferDesc, '0'); + } + } + } + // + // Print number without sign + // + _PrintUnsigned(pBufferDesc, (unsigned int)v, Base, NumDigits, FieldWidth, FormatFlags); +} + +/********************************************************************* +* +* _VPrintTarget() +* +* Function description +* Stores a formatted string. +* This data is read by the host. +* +* Parameters +* sFormat Pointer to format string. +* Options Options to be sent to the host. +* pParamList Pointer to the list of arguments for the format string. +*/ +static void _VPrintTarget(const char* sFormat, U32 Options, va_list* pParamList) { + SEGGER_SYSVIEW_PRINTF_DESC BufferDesc; + char c; + int v; + unsigned int NumDigits; + unsigned int FormatFlags; + unsigned int FieldWidth; + U8* pPayloadStart; +#if SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0 + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_MAX_STRING_LEN + 1 + 2 * SEGGER_SYSVIEW_QUANTA_U32); + SEGGER_SYSVIEW_LOCK(); +#else + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_MAX_STRING_LEN + 1 + 2 * SEGGER_SYSVIEW_QUANTA_U32); +#endif + +#if SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0 + BufferDesc.pBuffer = aPacket; +#else + BufferDesc.pBuffer = _aPacket; +#endif + BufferDesc.Cnt = 0u; + BufferDesc.pPayloadStart = pPayloadStart; + BufferDesc.pPayload = BufferDesc.pPayloadStart + 1u; + BufferDesc.Options = Options; + + do { + c = *sFormat; + sFormat++; + if (c == 0u) { + break; + } + if (c == '%') { + // + // Filter out flags + // + FormatFlags = 0u; + v = 1; + do { + c = *sFormat; + switch (c) { + case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break; + case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break; + case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break; + case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break; + default: v = 0; break; + } + } while (v); + // + // filter out field with + // + FieldWidth = 0u; + do { + c = *sFormat; + if ((c < '0') || (c > '9')) { + break; + } + sFormat++; + FieldWidth = (FieldWidth * 10u) + ((unsigned int)c - '0'); + } while (1); + + // + // Filter out precision (number of digits to display) + // + NumDigits = 0u; + c = *sFormat; + if (c == '.') { + sFormat++; + do { + c = *sFormat; + if ((c < '0') || (c > '9')) { + break; + } + sFormat++; + NumDigits = NumDigits * 10u + ((unsigned int)c - '0'); + } while (1); + } + // + // Filter out length modifier + // + c = *sFormat; + do { + if ((c == 'l') || (c == 'h')) { + c = *sFormat; + sFormat++; + } else { + break; + } + } while (1); + // + // Handle specifiers + // + switch (c) { + case 'c': { + char c0; + v = va_arg(*pParamList, int); + c0 = (char)v; + _StoreChar(&BufferDesc, c0); + break; + } + case 'd': + v = va_arg(*pParamList, int); + _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags); + break; + case 'u': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned int)v, 10u, NumDigits, FieldWidth, FormatFlags); + break; + case 'x': + case 'X': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned int)v, 16u, NumDigits, FieldWidth, FormatFlags); + break; + case 'p': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned int)v, 16u, 8u, 8u, 0u); + break; + case '%': + _StoreChar(&BufferDesc, '%'); + break; + default: + break; + } + sFormat++; + } else { + _StoreChar(&BufferDesc, c); + } + } while (*sFormat); + + // + // Write remaining data, if any + // + if (BufferDesc.Cnt != 0u) { + *(BufferDesc.pPayloadStart) = (U8)BufferDesc.Cnt; + ENCODE_U32(BufferDesc.pPayload, BufferDesc.Options); + ENCODE_U32(BufferDesc.pPayload, 0); + _SendPacket(BufferDesc.pPayloadStart, BufferDesc.pPayload, SYSVIEW_EVTID_PRINT_FORMATTED); + } +#if SEGGER_SYSVIEW_USE_STATIC_BUFFER == 0 + SEGGER_SYSVIEW_UNLOCK(); + RECORD_END(); +#else + RECORD_END(); +#endif +} +#endif // SEGGER_SYSVIEW_EXCLUDE_PRINTF + +/********************************************************************* +* +* Public code +* +********************************************************************** +*/ + +/********************************************************************* +* +* SEGGER_SYSVIEW_Init() +* +* Function description +* Initializes the SYSVIEW module. +* Must be called before the Systemview Application connects to +* the system. +* +* Parameters +* SysFreq - Frequency of timestamp, usually CPU core clock frequency. +* CPUFreq - CPU core clock frequency. +* pOSAPI - Pointer to the API structure for OS-specific functions. +* pfSendSysDesc - Pointer to record system description callback function. +* +* Additional information +* This function initializes the RTT channel used to transport +* SEGGER SystemView packets. +* The channel is assigned the label "SysView" for client software +* to identify the SystemView channel. +* +* The channel is configured with the macro SEGGER_SYSVIEW_RTT_CHANNEL. +*/ +void SEGGER_SYSVIEW_Init(U32 SysFreq, U32 CPUFreq, const SEGGER_SYSVIEW_OS_API *pOSAPI, SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC pfSendSysDesc) { +#ifdef SEGGER_RTT_SECTION + // + // Explicitly initialize the RTT Control Block if it is in its dedicated section. + // + SEGGER_RTT_Init(); +#endif +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) +#if SEGGER_SYSVIEW_RTT_CHANNEL > 0 + SEGGER_RTT_ConfigUpBuffer(SEGGER_SYSVIEW_RTT_CHANNEL, "SysView", &_UpBuffer[0], sizeof(_UpBuffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP); +#else + _SYSVIEW_Globals.UpChannel = (U8)SEGGER_RTT_AllocUpBuffer ("SysView", &_UpBuffer[0], sizeof(_UpBuffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP); +#endif + _SYSVIEW_Globals.RAMBaseAddress = SEGGER_SYSVIEW_ID_BASE; + _SYSVIEW_Globals.LastTxTimeStamp = SEGGER_SYSVIEW_GET_TIMESTAMP(); + _SYSVIEW_Globals.pOSAPI = pOSAPI; + _SYSVIEW_Globals.SysFreq = SysFreq; + _SYSVIEW_Globals.CPUFreq = CPUFreq; + _SYSVIEW_Globals.pfSendSysDesc = pfSendSysDesc; + _SYSVIEW_Globals.EnableState = 0; + _SYSVIEW_Globals.PacketCount = 0; +#else // (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) +#if SEGGER_SYSVIEW_RTT_CHANNEL > 0 + SEGGER_RTT_ConfigUpBuffer (SEGGER_SYSVIEW_RTT_CHANNEL, "SysView", &_UpBuffer[0], sizeof(_UpBuffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP); + SEGGER_RTT_ConfigDownBuffer (SEGGER_SYSVIEW_RTT_CHANNEL, "SysView", &_DownBuffer[0], sizeof(_DownBuffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP); +#else + _SYSVIEW_Globals.UpChannel = (U8)SEGGER_RTT_AllocUpBuffer ("SysView", &_UpBuffer[0], sizeof(_UpBuffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP); + _SYSVIEW_Globals.DownChannel = _SYSVIEW_Globals.UpChannel; + SEGGER_RTT_ConfigDownBuffer (_SYSVIEW_Globals.DownChannel, "SysView", &_DownBuffer[0], sizeof(_DownBuffer), SEGGER_RTT_MODE_NO_BLOCK_SKIP); +#endif + _SYSVIEW_Globals.RAMBaseAddress = SEGGER_SYSVIEW_ID_BASE; + _SYSVIEW_Globals.LastTxTimeStamp = SEGGER_SYSVIEW_GET_TIMESTAMP(); + _SYSVIEW_Globals.pOSAPI = pOSAPI; + _SYSVIEW_Globals.SysFreq = SysFreq; + _SYSVIEW_Globals.CPUFreq = CPUFreq; + _SYSVIEW_Globals.pfSendSysDesc = pfSendSysDesc; + _SYSVIEW_Globals.EnableState = 0; +#endif // (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_SetRAMBase() +* +* Function description +* Sets the RAM base address, which is subtracted from IDs in order +* to save bandwidth. +* +* Parameters +* RAMBaseAddress - Lowest RAM Address. (i.e. 0x20000000 on most Cortex-M) +*/ +void SEGGER_SYSVIEW_SetRAMBase(U32 RAMBaseAddress) { + _SYSVIEW_Globals.RAMBaseAddress = RAMBaseAddress; +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordVoid() +* +* Function description +* Formats and sends a SystemView packet with an empty payload. +* +* Parameters +* EventID - SystemView event ID. +*/ +void SEGGER_SYSVIEW_RecordVoid(unsigned int EventID) { + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE); + // + _SendPacket(pPayloadStart, pPayloadStart, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32() +* +* Function description +* Formats and sends a SystemView packet containing a single U32 +* parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Value - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32(unsigned int EventID, U32 Value) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Value); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x2() +* +* Function description +* Formats and sends a SystemView packet containing 2 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x2(unsigned int EventID, U32 Para0, U32 Para1) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x3() +* +* Function description +* Formats and sends a SystemView packet containing 3 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +* Para2 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x3(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 3 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + ENCODE_U32(pPayload, Para2); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x4() +* +* Function description +* Formats and sends a SystemView packet containing 4 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +* Para2 - The 32-bit parameter encoded to SystemView packet payload. +* Para3 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x4(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + ENCODE_U32(pPayload, Para2); + ENCODE_U32(pPayload, Para3); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x5() +* +* Function description +* Formats and sends a SystemView packet containing 5 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +* Para2 - The 32-bit parameter encoded to SystemView packet payload. +* Para3 - The 32-bit parameter encoded to SystemView packet payload. +* Para4 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x5(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 5 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + ENCODE_U32(pPayload, Para2); + ENCODE_U32(pPayload, Para3); + ENCODE_U32(pPayload, Para4); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x6() +* +* Function description +* Formats and sends a SystemView packet containing 6 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +* Para2 - The 32-bit parameter encoded to SystemView packet payload. +* Para3 - The 32-bit parameter encoded to SystemView packet payload. +* Para4 - The 32-bit parameter encoded to SystemView packet payload. +* Para5 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x6(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 6 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + ENCODE_U32(pPayload, Para2); + ENCODE_U32(pPayload, Para3); + ENCODE_U32(pPayload, Para4); + ENCODE_U32(pPayload, Para5); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x7() +* +* Function description +* Formats and sends a SystemView packet containing 7 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +* Para2 - The 32-bit parameter encoded to SystemView packet payload. +* Para3 - The 32-bit parameter encoded to SystemView packet payload. +* Para4 - The 32-bit parameter encoded to SystemView packet payload. +* Para5 - The 32-bit parameter encoded to SystemView packet payload. +* Para6 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x7(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 7 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + ENCODE_U32(pPayload, Para2); + ENCODE_U32(pPayload, Para3); + ENCODE_U32(pPayload, Para4); + ENCODE_U32(pPayload, Para5); + ENCODE_U32(pPayload, Para6); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x8() +* +* Function description +* Formats and sends a SystemView packet containing 8 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +* Para2 - The 32-bit parameter encoded to SystemView packet payload. +* Para3 - The 32-bit parameter encoded to SystemView packet payload. +* Para4 - The 32-bit parameter encoded to SystemView packet payload. +* Para5 - The 32-bit parameter encoded to SystemView packet payload. +* Para6 - The 32-bit parameter encoded to SystemView packet payload. +* Para7 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x8(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 8 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + ENCODE_U32(pPayload, Para2); + ENCODE_U32(pPayload, Para3); + ENCODE_U32(pPayload, Para4); + ENCODE_U32(pPayload, Para5); + ENCODE_U32(pPayload, Para6); + ENCODE_U32(pPayload, Para7); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x9() +* +* Function description +* Formats and sends a SystemView packet containing 9 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +* Para2 - The 32-bit parameter encoded to SystemView packet payload. +* Para3 - The 32-bit parameter encoded to SystemView packet payload. +* Para4 - The 32-bit parameter encoded to SystemView packet payload. +* Para5 - The 32-bit parameter encoded to SystemView packet payload. +* Para6 - The 32-bit parameter encoded to SystemView packet payload. +* Para7 - The 32-bit parameter encoded to SystemView packet payload. +* Para8 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x9(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7, U32 Para8) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 9 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + ENCODE_U32(pPayload, Para2); + ENCODE_U32(pPayload, Para3); + ENCODE_U32(pPayload, Para4); + ENCODE_U32(pPayload, Para5); + ENCODE_U32(pPayload, Para6); + ENCODE_U32(pPayload, Para7); + ENCODE_U32(pPayload, Para8); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordU32x10() +* +* Function description +* Formats and sends a SystemView packet containing 10 U32 parameter payload. +* +* Parameters +* EventID - SystemView event ID. +* Para0 - The 32-bit parameter encoded to SystemView packet payload. +* Para1 - The 32-bit parameter encoded to SystemView packet payload. +* Para2 - The 32-bit parameter encoded to SystemView packet payload. +* Para3 - The 32-bit parameter encoded to SystemView packet payload. +* Para4 - The 32-bit parameter encoded to SystemView packet payload. +* Para5 - The 32-bit parameter encoded to SystemView packet payload. +* Para6 - The 32-bit parameter encoded to SystemView packet payload. +* Para7 - The 32-bit parameter encoded to SystemView packet payload. +* Para8 - The 32-bit parameter encoded to SystemView packet payload. +* Para9 - The 32-bit parameter encoded to SystemView packet payload. +*/ +void SEGGER_SYSVIEW_RecordU32x10(unsigned int EventID, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7, U32 Para8, U32 Para9) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 10 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, Para0); + ENCODE_U32(pPayload, Para1); + ENCODE_U32(pPayload, Para2); + ENCODE_U32(pPayload, Para3); + ENCODE_U32(pPayload, Para4); + ENCODE_U32(pPayload, Para5); + ENCODE_U32(pPayload, Para6); + ENCODE_U32(pPayload, Para7); + ENCODE_U32(pPayload, Para8); + ENCODE_U32(pPayload, Para9); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordString() +* +* Function description +* Formats and sends a SystemView packet containing a string. +* +* Parameters +* EventID - SystemView event ID. +* pString - The string to be sent in the SystemView packet payload. +* +* Additional information +* The string is encoded as a count byte followed by the contents +* of the string. +* No more than SEGGER_SYSVIEW_MAX_STRING_LEN bytes will be encoded to the payload. +*/ +void SEGGER_SYSVIEW_RecordString(unsigned int EventID, const char* pString) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = _EncodeStr(pPayloadStart, pString, SEGGER_SYSVIEW_MAX_STRING_LEN); + _SendPacket(pPayloadStart, pPayload, EventID); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_Start() +* +* Function description +* Start recording SystemView events. +* +* This function is triggered by the SystemView Application on connect. +* For single-shot or post-mortem mode recording, it needs to be called +* by the application. +* +* Additional information +* This function enables transmission of SystemView packets recorded +* by subsequent trace calls and records a SystemView Start event. +* +* As part of start, a SystemView Init packet is sent, containing the system +* frequency. The list of current tasks, the current system time and the +* system description string is sent, too. +* +* Notes +* SEGGER_SYSVIEW_Start and SEGGER_SYSVIEW_Stop do not nest. +* When SEGGER_SYSVIEW_CAN_RESTART is 1, each received start command +* records the system information. This is required to enable restart +* of recordings when SystemView unexpectedly disconnects without sending +* a stop command before. +*/ +void SEGGER_SYSVIEW_Start(void) { +#if (SEGGER_SYSVIEW_CAN_RESTART == 0) + if (_SYSVIEW_Globals.EnableState == 0) { +#endif + _SYSVIEW_Globals.EnableState = 1; +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE == 1) + _SendSyncInfo(); +#else + SEGGER_SYSVIEW_LOCK(); + SEGGER_RTT_WriteSkipNoLock(CHANNEL_ID_UP, _abSync, 10); + SEGGER_SYSVIEW_UNLOCK(); + SEGGER_SYSVIEW_ON_EVENT_RECORDED(10); + SEGGER_SYSVIEW_RecordVoid(SYSVIEW_EVTID_TRACE_START); + { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, _SYSVIEW_Globals.SysFreq); + ENCODE_U32(pPayload, _SYSVIEW_Globals.CPUFreq); + ENCODE_U32(pPayload, _SYSVIEW_Globals.RAMBaseAddress); + ENCODE_U32(pPayload, SEGGER_SYSVIEW_ID_SHIFT); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_INIT); + RECORD_END(); + } + if (_SYSVIEW_Globals.pfSendSysDesc) { + _SYSVIEW_Globals.pfSendSysDesc(); + } + SEGGER_SYSVIEW_RecordSystime(); + SEGGER_SYSVIEW_SendTaskList(); + SEGGER_SYSVIEW_SendNumModules(); +#endif +#if (SEGGER_SYSVIEW_CAN_RESTART == 0) + } +#endif +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_Stop() +* +* Function description +* Stop recording SystemView events. +* +* This function is triggered by the SystemView Application on disconnect. +* For single-shot or post-mortem mode recording, it can be called +* by the application. +* +* Additional information +* This function disables transmission of SystemView packets recorded +* by subsequent trace calls. If transmission is enabled when +* this function is called, a single SystemView Stop event is recorded +* to the trace, send, and then trace transmission is halted. +*/ +void SEGGER_SYSVIEW_Stop(void) { + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE); + // + if (_SYSVIEW_Globals.EnableState) { + _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_TRACE_STOP); + _SYSVIEW_Globals.EnableState = 0; + } + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_GetChannelID() +* +* Function description +* Returns the RTT / channel ID used by SystemView. +*/ +int SEGGER_SYSVIEW_GetChannelID(void) { + return CHANNEL_ID_UP; +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_GetSysDesc() +* +* Function description +* Triggers a send of the system information and description. +* +*/ +void SEGGER_SYSVIEW_GetSysDesc(void) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, _SYSVIEW_Globals.SysFreq); + ENCODE_U32(pPayload, _SYSVIEW_Globals.CPUFreq); + ENCODE_U32(pPayload, _SYSVIEW_Globals.RAMBaseAddress); + ENCODE_U32(pPayload, SEGGER_SYSVIEW_ID_SHIFT); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_INIT); + RECORD_END(); + if (_SYSVIEW_Globals.pfSendSysDesc) { + _SYSVIEW_Globals.pfSendSysDesc(); + } +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_SendTaskInfo() +* +* Function description +* Send a Task Info Packet, containing TaskId for identification, +* task priority and task name. +* +* Parameters +* pInfo - Pointer to task information to send. +*/ +void SEGGER_SYSVIEW_SendTaskInfo(const SEGGER_SYSVIEW_TASKINFO *pInfo) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32 + 1 + 32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, SHRINK_ID(pInfo->TaskID)); + ENCODE_U32(pPayload, pInfo->Prio); + pPayload = _EncodeStr(pPayload, pInfo->sName, 32); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_INFO); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, SHRINK_ID(pInfo->TaskID)); + ENCODE_U32(pPayload, pInfo->StackBase); + ENCODE_U32(pPayload, pInfo->StackSize); + ENCODE_U32(pPayload, 0); // Stack End, future use + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_STACK_INFO); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_SendTaskList() +* +* Function description +* Send all tasks descriptors to the host. +*/ +void SEGGER_SYSVIEW_SendTaskList(void) { + if (_SYSVIEW_Globals.pOSAPI && _SYSVIEW_Globals.pOSAPI->pfSendTaskList) { + _SYSVIEW_Globals.pOSAPI->pfSendTaskList(); + } +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_SendSysDesc() +* +* Function description +* Send the system description string to the host. +* The system description is used by the Systemview Application +* to identify the current application and handle events accordingly. +* +* The system description is usually called by the system description +* callback, to ensure it is only sent when the SystemView Application +* is connected. +* +* Parameters +* sSysDesc - Pointer to the 0-terminated system description string. +* +* Additional information +* One system description string may not exceed SEGGER_SYSVIEW_MAX_STRING_LEN characters. +* Multiple description strings can be recorded. +* +* The Following items can be described in a system description string. +* Each item is identified by its identifier, followed by '=' and the value. +* Items are separated by ','. +*/ +void SEGGER_SYSVIEW_SendSysDesc(const char *sSysDesc) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = _EncodeStr(pPayloadStart, sSysDesc, SEGGER_SYSVIEW_MAX_STRING_LEN); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_SYSDESC); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordSystime() +* +* Function description +* Formats and sends a SystemView Systime containing a single U64 or U32 +* parameter payload. +*/ +void SEGGER_SYSVIEW_RecordSystime(void) { + U64 Systime; + + if (_SYSVIEW_Globals.pOSAPI && _SYSVIEW_Globals.pOSAPI->pfGetTime) { + Systime = _SYSVIEW_Globals.pOSAPI->pfGetTime(); + SEGGER_SYSVIEW_RecordU32x2(SYSVIEW_EVTID_SYSTIME_US, + (U32)(Systime), + (U32)(Systime >> 32)); + } else { + SEGGER_SYSVIEW_RecordU32(SYSVIEW_EVTID_SYSTIME_CYCLES, SEGGER_SYSVIEW_GET_TIMESTAMP()); + } +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordEnterISR() +* +* Function description +* Format and send an ISR entry event. +* +* Additional information +* Example packets sent +* 02 0F 50 // ISR(15) Enter. Timestamp is 80 (0x50) +*/ +void SEGGER_SYSVIEW_RecordEnterISR(void) { + unsigned v; + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + v = SEGGER_SYSVIEW_GET_INTERRUPT_ID(); + ENCODE_U32(pPayload, v); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_ISR_ENTER); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordExitISR() +* +* Function description +* Format and send an ISR exit event. +* +* Additional information +* Format as follows: +* 03 // Max. packet len is 6 +* +* Example packets sent +* 03 20 // ISR Exit. Timestamp is 32 (0x20) +*/ +void SEGGER_SYSVIEW_RecordExitISR(void) { + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE); + // + _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_ISR_EXIT); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordExitISRToScheduler() +* +* Function description +* Format and send an ISR exit into scheduler event. +* +* Additional information +* Format as follows: +* 18 // Max. packet len is 6 +* +* Example packets sent +* 18 20 // ISR Exit to Scheduler. Timestamp is 32 (0x20) +*/ +void SEGGER_SYSVIEW_RecordExitISRToScheduler(void) { + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE); + // + _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_ISR_TO_SCHEDULER); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordEnterTimer() +* +* Function description +* Format and send a Timer entry event. +* +* Parameters +* TimerId - Id of the timer which starts. +*/ +void SEGGER_SYSVIEW_RecordEnterTimer(U32 TimerId) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, SHRINK_ID(TimerId)); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TIMER_ENTER); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordExitTimer() +* +* Function description +* Format and send a Timer exit event. +*/ +void SEGGER_SYSVIEW_RecordExitTimer(void) { + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE); + // + _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_TIMER_EXIT); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordEndCall() +* +* Function description +* Format and send an End API Call event without return value. +* +* Parameters +* EventID - Id of API function which ends. +*/ +void SEGGER_SYSVIEW_RecordEndCall(unsigned int EventID) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, EventID); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_END_CALL); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordEndCallU32() +* +* Function description +* Format and send an End API Call event with return value. +* +* Parameters +* EventID - Id of API function which ends. +* Para0 - Return value which will be returned by the API function. +*/ +void SEGGER_SYSVIEW_RecordEndCallU32(unsigned int EventID, U32 Para0) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, EventID); + ENCODE_U32(pPayload, Para0); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_END_CALL); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_OnIdle() +* +* Function description +* Record an Idle event. +*/ +void SEGGER_SYSVIEW_OnIdle(void) { + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE); + // + _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_IDLE); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_OnTaskCreate() +* +* Function description +* Record a Task Create event. The Task Create event corresponds +* to creating a task in the OS. +* +* Parameters +* TaskId - Task ID of created task. +*/ +void SEGGER_SYSVIEW_OnTaskCreate(U32 TaskId) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + TaskId = SHRINK_ID(TaskId); + ENCODE_U32(pPayload, TaskId); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_CREATE); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_OnTaskTerminate() +* +* Function description +* Record a Task termination event. +* The Task termination event corresponds to terminating a task in +* the OS. If the TaskId is the currently active task, +* SEGGER_SYSVIEW_OnTaskStopExec may be used, either. +* +* Parameters +* TaskId - Task ID of terminated task. +*/ +void SEGGER_SYSVIEW_OnTaskTerminate(U32 TaskId) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + TaskId = SHRINK_ID(TaskId); + ENCODE_U32(pPayload, TaskId); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_TERMINATE); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_OnTaskStartExec() +* +* Function description +* Record a Task Start Execution event. The Task Start event +* corresponds to when a task has started to execute rather than +* when it is ready to execute. +* +* Parameters +* TaskId - Task ID of task that started to execute. +*/ +void SEGGER_SYSVIEW_OnTaskStartExec(U32 TaskId) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + TaskId = SHRINK_ID(TaskId); + ENCODE_U32(pPayload, TaskId); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_START_EXEC); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_OnTaskStopExec() +* +* Function description +* Record a Task Stop Execution event. The Task Stop event +* corresponds to when a task stops executing and terminates. +*/ +void SEGGER_SYSVIEW_OnTaskStopExec(void) { + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE); + // + _SendPacket(pPayloadStart, pPayloadStart, SYSVIEW_EVTID_TASK_STOP_EXEC); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_OnTaskStartReady() +* +* Function description +* Record a Task Start Ready event. +* +* Parameters +* TaskId - Task ID of task that started to execute. +*/ +void SEGGER_SYSVIEW_OnTaskStartReady(U32 TaskId) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + TaskId = SHRINK_ID(TaskId); + ENCODE_U32(pPayload, TaskId); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_START_READY); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_OnTaskStopReady() +* +* Function description +* Record a Task Stop Ready event. +* +* Parameters +* TaskId - Task ID of task that completed execution. +* Cause - Reason for task to stop (i.e. Idle/Sleep) +*/ +void SEGGER_SYSVIEW_OnTaskStopReady(U32 TaskId, unsigned int Cause) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + TaskId = SHRINK_ID(TaskId); + ENCODE_U32(pPayload, TaskId); + ENCODE_U32(pPayload, Cause); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_TASK_STOP_READY); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_MarkStart() +* +* Function description +* Record a Performance Marker Start event to start measuring runtime. +* +* Parameters +* MarkerId - User defined ID for the marker. +*/ +void SEGGER_SYSVIEW_MarkStart(unsigned MarkerId) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, MarkerId); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_MARK_START); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_MarkStop() +* +* Function description +* Record a Performance Marker Stop event to stop measuring runtime. +* +* Parameters +* MarkerId - User defined ID for the marker. +*/ +void SEGGER_SYSVIEW_MarkStop(unsigned MarkerId) { + U8 * pPayload; + U8 * pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, MarkerId); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_MARK_STOP); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_Mark() +* +* Function description +* Record a Performance Marker intermediate event. +* +* Parameters +* MarkerId - User defined ID for the marker. +*/ +void SEGGER_SYSVIEW_Mark(unsigned int MarkerId) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_MARK); + ENCODE_U32(pPayload, MarkerId); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_NameMarker() +* +* Function description +* Send the name of a Performance Marker to be displayed in SystemView. +* +* Marker names are usually set in the system description +* callback, to ensure it is only sent when the SystemView Application +* is connected. +* +* Parameters +* MarkerId - User defined ID for the marker. +* sName - Pointer to the marker name. (Max. SEGGER_SYSVIEW_MAX_STRING_LEN Bytes) +*/ +void SEGGER_SYSVIEW_NameMarker(unsigned int MarkerId, const char* sName) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, SYSVIEW_EVTID_EX_NAME_MARKER); + ENCODE_U32(pPayload, MarkerId); + pPayload = _EncodeStr(pPayload, sName, SEGGER_SYSVIEW_MAX_STRING_LEN); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_EX); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_NameResource() +* +* Function description +* Send the name of a resource to be displayed in SystemView. +* +* Marker names are usually set in the system description +* callback, to ensure it is only sent when the SystemView Application +* is connected. +* +* Parameters +* ResourceId - Id of the resource to be named. i.e. its address. +* sName - Pointer to the resource name. (Max. SEGGER_SYSVIEW_MAX_STRING_LEN Bytes) +*/ +void SEGGER_SYSVIEW_NameResource(U32 ResourceId, const char* sName) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = pPayloadStart; + ENCODE_U32(pPayload, SHRINK_ID(ResourceId)); + pPayload = _EncodeStr(pPayload, sName, SEGGER_SYSVIEW_MAX_STRING_LEN); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_NAME_RESOURCE); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_SendPacket() +* +* Function description +* Send an event packet. +* +* Parameters +* pPacket - Pointer to the start of the packet. +* pPayloadEnd - Pointer to the end of the payload. +* Make sure there are at least 5 bytes free after the payload. +* EventId - Id of the event packet. +* +* Return value +* !=0: Success, Message sent. +* ==0: Buffer full, Message *NOT* sent. +*/ +int SEGGER_SYSVIEW_SendPacket(U8* pPacket, U8* pPayloadEnd, unsigned int EventId) { +#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 1) + SEGGER_SYSVIEW_LOCK(); +#endif + _SendPacket(pPacket + 4, pPayloadEnd, EventId); +#if (SEGGER_SYSVIEW_USE_STATIC_BUFFER == 1) + SEGGER_SYSVIEW_UNLOCK(); +#endif + return 0; +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_EncodeU32() +* +* Function description +* Encode a U32 in variable-length format. +* +* Parameters +* pPayload - Pointer to where U32 will be encoded. +* Value - The 32-bit value to be encoded. +* +* Return value +* Pointer to the byte following the value, i.e. the first free +* byte in the payload and the next position to store payload +* content. +*/ +U8* SEGGER_SYSVIEW_EncodeU32(U8* pPayload, U32 Value) { + ENCODE_U32(pPayload, Value); + return pPayload; +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_EncodeString() +* +* Function description +* Encode a string in variable-length format. +* +* Parameters +* pPayload - Pointer to where string will be encoded. +* s - String to encode. +* MaxLen - Maximum number of characters to encode from string. +* +* Return value +* Pointer to the byte following the value, i.e. the first free +* byte in the payload and the next position to store payload +* content. +* +* Additional information +* The string is encoded as a count byte followed by the contents +* of the string. +* No more than 1 + MaxLen bytes will be encoded to the payload. +*/ +U8* SEGGER_SYSVIEW_EncodeString(U8* pPayload, const char* s, unsigned int MaxLen) { + return _EncodeStr(pPayload, s, MaxLen); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_EncodeData() +* +* Function description +* Encode a byte buffer in variable-length format. +* +* Parameters +* pPayload - Pointer to where string will be encoded. +* pSrc - Pointer to data buffer to be encoded. +* NumBytes - Number of bytes in the buffer to be encoded. +* +* Return value +* Pointer to the byte following the value, i.e. the first free +* byte in the payload and the next position to store payload +* content. +* +* Additional information +* The data is encoded as a count byte followed by the contents +* of the data buffer. +* Make sure NumBytes + 1 bytes are free for the payload. +*/ +U8* SEGGER_SYSVIEW_EncodeData(U8 *pPayload, const char* pSrc, unsigned int NumBytes) { + return _EncodeData(pPayload, pSrc, NumBytes); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_EncodeId() +* +* Function description +* Encode a 32-bit Id in shrunken variable-length format. +* +* Parameters +* pPayload - Pointer to where the Id will be encoded. +* Id - The 32-bit value to be encoded. +* +* Return value +* Pointer to the byte following the value, i.e. the first free +* byte in the payload and the next position to store payload +* content. +* +* Additional information +* The parameters to shrink an Id can be configured in +* SEGGER_SYSVIEW_Conf.h and via SEGGER_SYSVIEW_SetRAMBase(). +* SEGGER_SYSVIEW_ID_BASE: Lowest Id reported by the application. +* (i.e. 0x20000000 when all Ids are an address in this RAM) +* SEGGER_SYSVIEW_ID_SHIFT: Number of bits to shift the Id to +* save bandwidth. (i.e. 2 when Ids are 4 byte aligned) +*/ +U8* SEGGER_SYSVIEW_EncodeId(U8* pPayload, U32 Id) { + Id = SHRINK_ID(Id); + ENCODE_U32(pPayload, Id); + return pPayload; +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_ShrinkId() +* +* Function description +* Get the shrunken value of an Id for further processing like in +* SEGGER_SYSVIEW_NameResource(). +* +* Parameters +* Id - The 32-bit value to be shrunken. +* +* Return value +* Shrunken Id. +* +* Additional information +* The parameters to shrink an Id can be configured in +* SEGGER_SYSVIEW_Conf.h and via SEGGER_SYSVIEW_SetRAMBase(). +* SEGGER_SYSVIEW_ID_BASE: Lowest Id reported by the application. +* (i.e. 0x20000000 when all Ids are an address in this RAM) +* SEGGER_SYSVIEW_ID_SHIFT: Number of bits to shift the Id to +* save bandwidth. (i.e. 2 when Ids are 4 byte aligned) +*/ +U32 SEGGER_SYSVIEW_ShrinkId(U32 Id) { + return SHRINK_ID(Id); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RegisterModule() +* +* Function description +* Register a middleware module for recording its events. +* +* Parameters +* pModule - The middleware module information. +* +* Additional information +* SEGGER_SYSVIEW_MODULE elements: +* sDescription - Pointer to a string containing the module name and optionally the module event description. +* NumEvents - Number of events the module wants to register. +* EventOffset - Offset to be added to the event Ids. Out parameter, set by this function. Do not modify after calling this function. +* pfSendModuleDesc - Callback function pointer to send more detailed module description to SystemView Application. +* pNext - Pointer to next registered module. Out parameter, set by this function. Do not modify after calling this function. +*/ +void SEGGER_SYSVIEW_RegisterModule(SEGGER_SYSVIEW_MODULE* pModule) { + SEGGER_SYSVIEW_LOCK(); + if (_pFirstModule == 0) { + // + // No module registered, yet. + // Start list with new module. + // EventOffset is the base offset for modules + // + pModule->EventOffset = MODULE_EVENT_OFFSET; + pModule->pNext = 0; + _pFirstModule = pModule; + _NumModules = 1; + } else { + // + // Registreded module(s) present. + // Prepend new module in list. + // EventOffset set from number of events and offset of previous module. + // + pModule->EventOffset = _pFirstModule->EventOffset + _pFirstModule->NumEvents; + pModule->pNext = _pFirstModule; + _pFirstModule = pModule; + _NumModules++; + } + SEGGER_SYSVIEW_SendModule(0); + if (pModule->pfSendModuleDesc) { + pModule->pfSendModuleDesc(); + } + SEGGER_SYSVIEW_UNLOCK(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_RecordModuleDescription() +* +* Function description +* Sends detailed information of a registered module to the host. +* +* Parameters +* pModule - Pointer to the described module. +* sDescription - Pointer to a description string. +*/ +void SEGGER_SYSVIEW_RecordModuleDescription(const SEGGER_SYSVIEW_MODULE* pModule, const char* sDescription) { + U8 ModuleId; + SEGGER_SYSVIEW_MODULE* p; + + p = _pFirstModule; + ModuleId = 0; + do { + if (p == pModule) { + break; + } + ModuleId++; + p = p->pNext; + } while (p); + { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = pPayloadStart; + // + // Send module description + // Send event offset and number of events + // + ENCODE_U32(pPayload, ModuleId); + ENCODE_U32(pPayload, (pModule->EventOffset)); + pPayload = _EncodeStr(pPayload, sDescription, SEGGER_SYSVIEW_MAX_STRING_LEN); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_MODULEDESC); + RECORD_END(); + } +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_SendModule() +* +* Function description +* Sends the information of a registered module to the host. +* +* Parameters +* ModuleId - Id of the requested module. +*/ +void SEGGER_SYSVIEW_SendModule(U8 ModuleId) { + SEGGER_SYSVIEW_MODULE* pModule; + U32 n; + + if (_pFirstModule != 0) { + pModule = _pFirstModule; + for (n = 0; n < ModuleId; n++) { + pModule = pModule->pNext; + if (pModule == 0) { + break; + } + } + if (pModule != 0) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + 1 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = pPayloadStart; + // + // Send module description + // Send event offset and number of events + // + ENCODE_U32(pPayload, ModuleId); + ENCODE_U32(pPayload, (pModule->EventOffset)); + pPayload = _EncodeStr(pPayload, pModule->sModule, SEGGER_SYSVIEW_MAX_STRING_LEN); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_MODULEDESC); + RECORD_END(); + } + } +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_SendModuleDescription() +* +* Function description +* Triggers a send of the registered module descriptions. +* +*/ +void SEGGER_SYSVIEW_SendModuleDescription(void) { + SEGGER_SYSVIEW_MODULE* pModule; + + if (_pFirstModule != 0) { + pModule = _pFirstModule; + do { + if (pModule->pfSendModuleDesc) { + pModule->pfSendModuleDesc(); + } + pModule = pModule->pNext; + } while (pModule); + } +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_SendNumModules() +* +* Function description +* Send the number of registered modules to the host. +*/ +void SEGGER_SYSVIEW_SendNumModules(void) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2*SEGGER_SYSVIEW_QUANTA_U32); + pPayload = pPayloadStart; + ENCODE_U32(pPayload, _NumModules); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_NUMMODULES); + RECORD_END(); +} + +#ifndef SEGGER_SYSVIEW_EXCLUDE_PRINTF // Define in project to avoid warnings about variable parameter list + +/********************************************************************* +* +* SEGGER_SYSVIEW_PrintfHostEx() +* +* Function description +* Print a string which is formatted on the host by the SystemView Application +* with Additional information. +* +* Parameters +* s - String to be formatted. +* Options - Options for the string. i.e. Log level. +* +* Additional information +* All format arguments are treated as 32-bit scalar values. +*/ +void SEGGER_SYSVIEW_PrintfHostEx(const char* s, U32 Options, ...) { + va_list ParamList; +#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT + int r; + + va_start(ParamList, Options); + r = _VPrintHost(s, Options, &ParamList); + va_end(ParamList); + + if (r == -1) { + va_start(ParamList, Options); + _VPrintTarget(s, Options, &ParamList); + va_end(ParamList); + } +#else + va_start(ParamList, Options); + _VPrintHost(s, Options, &ParamList); + va_end(ParamList); +#endif +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_PrintfHost() +* +* Function description +* Print a string which is formatted on the host by the SystemView Application. +* +* Parameters +* s - String to be formatted. +* +* Additional information +* All format arguments are treated as 32-bit scalar values. +*/ +void SEGGER_SYSVIEW_PrintfHost(const char* s, ...) { + va_list ParamList; +#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT + int r; + + va_start(ParamList, s); + r = _VPrintHost(s, SEGGER_SYSVIEW_LOG, &ParamList); + va_end(ParamList); + + if (r == -1) { + va_start(ParamList, s); + _VPrintTarget(s, SEGGER_SYSVIEW_LOG, &ParamList); + va_end(ParamList); + } +#else + va_start(ParamList, s); + _VPrintHost(s, SEGGER_SYSVIEW_LOG, &ParamList); + va_end(ParamList); +#endif +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_WarnfHost() +* +* Function description +* Print a warning string which is formatted on the host by +* the SystemView Application. +* +* Parameters +* s - String to be formatted. +* +* Additional information +* All format arguments are treated as 32-bit scalar values. +*/ +void SEGGER_SYSVIEW_WarnfHost(const char* s, ...) { + va_list ParamList; +#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT + int r; + + va_start(ParamList, s); + r = _VPrintHost(s, SEGGER_SYSVIEW_WARNING, &ParamList); + va_end(ParamList); + + if (r == -1) { + va_start(ParamList, s); + _VPrintTarget(s, SEGGER_SYSVIEW_WARNING, &ParamList); + va_end(ParamList); + } +#else + va_start(ParamList, s); + _VPrintHost(s, SEGGER_SYSVIEW_WARNING, &ParamList); + va_end(ParamList); +#endif +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_ErrorfHost() +* +* Function description +* Print an error string which is formatted on the host by +* the SystemView Application. +* +* Parameters +* s - String to be formatted. +* +* Additional information +* All format arguments are treated as 32-bit scalar values. +*/ +void SEGGER_SYSVIEW_ErrorfHost(const char* s, ...) { + va_list ParamList; +#if SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT + int r; + + va_start(ParamList, s); + r = _VPrintHost(s, SEGGER_SYSVIEW_ERROR, &ParamList); + va_end(ParamList); + + if (r == -1) { + va_start(ParamList, s); + _VPrintTarget(s, SEGGER_SYSVIEW_ERROR, &ParamList); + va_end(ParamList); + } +#else + va_start(ParamList, s); + _VPrintHost(s, SEGGER_SYSVIEW_ERROR, &ParamList); + va_end(ParamList); +#endif +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_PrintfTargetEx() +* +* Function description +* Print a string which is formatted on the target before sent to +* the host with Additional information. +* +* Parameters +* s - String to be formatted. +* Options - Options for the string. i.e. Log level. +*/ +void SEGGER_SYSVIEW_PrintfTargetEx(const char* s, U32 Options, ...) { + va_list ParamList; + + va_start(ParamList, Options); + _VPrintTarget(s, Options, &ParamList); + va_end(ParamList); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_PrintfTarget() +* +* Function description +* Print a string which is formatted on the target before sent to +* the host. +* +* Parameters +* s - String to be formatted. +*/ +void SEGGER_SYSVIEW_PrintfTarget(const char* s, ...) { + va_list ParamList; + + va_start(ParamList, s); + _VPrintTarget(s, SEGGER_SYSVIEW_LOG, &ParamList); + va_end(ParamList); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_WarnfTarget() +* +* Function description +* Print a warning string which is formatted on the target before +* sent to the host. +* +* Parameters +* s - String to be formatted. +*/ +void SEGGER_SYSVIEW_WarnfTarget(const char* s, ...) { + va_list ParamList; + + va_start(ParamList, s); + _VPrintTarget(s, SEGGER_SYSVIEW_WARNING, &ParamList); + va_end(ParamList); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_ErrorfTarget() +* +* Function description +* Print an error string which is formatted on the target before +* sent to the host. +* +* Parameters +* s - String to be formatted. +*/ +void SEGGER_SYSVIEW_ErrorfTarget(const char* s, ...) { + va_list ParamList; + + va_start(ParamList, s); + _VPrintTarget(s, SEGGER_SYSVIEW_ERROR, &ParamList); + va_end(ParamList); +} +#endif // SEGGER_SYSVIEW_EXCLUDE_PRINTF + +/********************************************************************* +* +* SEGGER_SYSVIEW_Print() +* +* Function description +* Print a string to the host. +* +* Parameters +* s - String to sent. +*/ +void SEGGER_SYSVIEW_Print(const char* s) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN); + ENCODE_U32(pPayload, SEGGER_SYSVIEW_LOG); + ENCODE_U32(pPayload, 0); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_Warn() +* +* Function description +* Print a warning string to the host. +* +* Parameters +* s - String to sent. +*/ +void SEGGER_SYSVIEW_Warn(const char* s) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN); + ENCODE_U32(pPayload, SEGGER_SYSVIEW_WARNING); + ENCODE_U32(pPayload, 0); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_Error() +* +* Function description +* Print an error string to the host. +* +* Parameters +* s - String to sent. +*/ +void SEGGER_SYSVIEW_Error(const char* s) { + U8* pPayload; + U8* pPayloadStart; + RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN); + // + pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN); + ENCODE_U32(pPayload, SEGGER_SYSVIEW_ERROR); + ENCODE_U32(pPayload, 0); + _SendPacket(pPayloadStart, pPayload, SYSVIEW_EVTID_PRINT_FORMATTED); + RECORD_END(); +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_EnableEvents() +* +* Function description +* Enable standard SystemView events to be generated. +* +* Parameters +* EnableMask - Events to be enabled. +*/ +void SEGGER_SYSVIEW_EnableEvents(U32 EnableMask) { + _SYSVIEW_Globals.DisabledEvents &= ~EnableMask; +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_DisableEvents() +* +* Function description +* Disable standard SystemView events to not be generated. +* +* Parameters +* DisableMask - Events to be disabled. +*/ +void SEGGER_SYSVIEW_DisableEvents(U32 DisableMask) { + _SYSVIEW_Globals.DisabledEvents |= DisableMask; +} + +/********************************************************************* +* +* SEGGER_SYSVIEW_IsStarted() +* +* Function description +* Handle incoming packets if any and check if recording is started. +* +* Return value +* 0: Recording not started. +* > 0: Recording started. +*/ +int SEGGER_SYSVIEW_IsStarted(void) { +#if (SEGGER_SYSVIEW_POST_MORTEM_MODE != 1) + // + // Check if host is sending data which needs to be processed. + // + if (SEGGER_RTT_HASDATA(CHANNEL_ID_DOWN)) { + if (_SYSVIEW_Globals.RecursionCnt == 0) { // Avoid uncontrolled nesting. This way, this routine can call itself once, but no more often than that. + _SYSVIEW_Globals.RecursionCnt = 1; + _HandleIncomingPacket(); + _SYSVIEW_Globals.RecursionCnt = 0; + } + } +#endif + return _SYSVIEW_Globals.EnableState; +} + + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_SYSVIEW.h b/bsp/projects/common/segger/SEGGER_SYSVIEW.h new file mode 100644 index 0000000..7dc56a3 --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_SYSVIEW.h @@ -0,0 +1,370 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +-------------------------- END-OF-HEADER ----------------------------- +File : SEGGER_SYSVIEW.h +Purpose : System visualization API. +Revision: $Rev: 26226 $ +*/ + +#ifndef SEGGER_SYSVIEW_H +#define SEGGER_SYSVIEW_H + +/********************************************************************* +* +* #include Section +* +********************************************************************** +*/ + +#include "SEGGER.h" +#include "SEGGER_SYSVIEW_ConfDefaults.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ + +#define SEGGER_SYSVIEW_MAJOR 3 +#define SEGGER_SYSVIEW_MINOR 32 +#define SEGGER_SYSVIEW_REV 0 +#define SEGGER_SYSVIEW_VERSION ((SEGGER_SYSVIEW_MAJOR * 10000) + (SEGGER_SYSVIEW_MINOR * 100) + SEGGER_SYSVIEW_REV) + +#define SEGGER_SYSVIEW_INFO_SIZE 9 // Minimum size, which has to be reserved for a packet. 1-2 byte of message type, 0-2 byte of payload length, 1-5 bytes of timestamp. +#define SEGGER_SYSVIEW_QUANTA_U32 5 // Maximum number of bytes to encode a U32, should be reserved for each 32-bit value in a packet. + +#define SEGGER_SYSVIEW_LOG (0u) +#define SEGGER_SYSVIEW_WARNING (1u) +#define SEGGER_SYSVIEW_ERROR (2u) +#define SEGGER_SYSVIEW_FLAG_APPEND (1u << 6) + +#define SEGGER_SYSVIEW_PREPARE_PACKET(p) (p) + 4 +// +// SystemView events. First 32 IDs from 0 .. 31 are reserved for these +// +#define SYSVIEW_EVTID_NOP 0 // Dummy packet. +#define SYSVIEW_EVTID_OVERFLOW 1 +#define SYSVIEW_EVTID_ISR_ENTER 2 +#define SYSVIEW_EVTID_ISR_EXIT 3 +#define SYSVIEW_EVTID_TASK_START_EXEC 4 +#define SYSVIEW_EVTID_TASK_STOP_EXEC 5 +#define SYSVIEW_EVTID_TASK_START_READY 6 +#define SYSVIEW_EVTID_TASK_STOP_READY 7 +#define SYSVIEW_EVTID_TASK_CREATE 8 +#define SYSVIEW_EVTID_TASK_INFO 9 +#define SYSVIEW_EVTID_TRACE_START 10 +#define SYSVIEW_EVTID_TRACE_STOP 11 +#define SYSVIEW_EVTID_SYSTIME_CYCLES 12 +#define SYSVIEW_EVTID_SYSTIME_US 13 +#define SYSVIEW_EVTID_SYSDESC 14 +#define SYSVIEW_EVTID_MARK_START 15 +#define SYSVIEW_EVTID_MARK_STOP 16 +#define SYSVIEW_EVTID_IDLE 17 +#define SYSVIEW_EVTID_ISR_TO_SCHEDULER 18 +#define SYSVIEW_EVTID_TIMER_ENTER 19 +#define SYSVIEW_EVTID_TIMER_EXIT 20 +#define SYSVIEW_EVTID_STACK_INFO 21 +#define SYSVIEW_EVTID_MODULEDESC 22 + +#define SYSVIEW_EVTID_INIT 24 +#define SYSVIEW_EVTID_NAME_RESOURCE 25 +#define SYSVIEW_EVTID_PRINT_FORMATTED 26 +#define SYSVIEW_EVTID_NUMMODULES 27 +#define SYSVIEW_EVTID_END_CALL 28 +#define SYSVIEW_EVTID_TASK_TERMINATE 29 + +#define SYSVIEW_EVTID_EX 31 +// +// SystemView extended events. Sent with ID 31. +// +#define SYSVIEW_EVTID_EX_MARK 0 +#define SYSVIEW_EVTID_EX_NAME_MARKER 1 +// +// Event masks to disable/enable events +// +#define SYSVIEW_EVTMASK_NOP (1 << SYSVIEW_EVTID_NOP) +#define SYSVIEW_EVTMASK_OVERFLOW (1 << SYSVIEW_EVTID_OVERFLOW) +#define SYSVIEW_EVTMASK_ISR_ENTER (1 << SYSVIEW_EVTID_ISR_ENTER) +#define SYSVIEW_EVTMASK_ISR_EXIT (1 << SYSVIEW_EVTID_ISR_EXIT) +#define SYSVIEW_EVTMASK_TASK_START_EXEC (1 << SYSVIEW_EVTID_TASK_START_EXEC) +#define SYSVIEW_EVTMASK_TASK_STOP_EXEC (1 << SYSVIEW_EVTID_TASK_STOP_EXEC) +#define SYSVIEW_EVTMASK_TASK_START_READY (1 << SYSVIEW_EVTID_TASK_START_READY) +#define SYSVIEW_EVTMASK_TASK_STOP_READY (1 << SYSVIEW_EVTID_TASK_STOP_READY) +#define SYSVIEW_EVTMASK_TASK_CREATE (1 << SYSVIEW_EVTID_TASK_CREATE) +#define SYSVIEW_EVTMASK_TASK_INFO (1 << SYSVIEW_EVTID_TASK_INFO) +#define SYSVIEW_EVTMASK_TRACE_START (1 << SYSVIEW_EVTID_TRACE_START) +#define SYSVIEW_EVTMASK_TRACE_STOP (1 << SYSVIEW_EVTID_TRACE_STOP) +#define SYSVIEW_EVTMASK_SYSTIME_CYCLES (1 << SYSVIEW_EVTID_SYSTIME_CYCLES) +#define SYSVIEW_EVTMASK_SYSTIME_US (1 << SYSVIEW_EVTID_SYSTIME_US) +#define SYSVIEW_EVTMASK_SYSDESC (1 << SYSVIEW_EVTID_SYSDESC) +#define SYSVIEW_EVTMASK_USER_START (1 << SYSVIEW_EVTID_USER_START) +#define SYSVIEW_EVTMASK_USER_STOP (1 << SYSVIEW_EVTID_USER_STOP) +#define SYSVIEW_EVTMASK_IDLE (1 << SYSVIEW_EVTID_IDLE) +#define SYSVIEW_EVTMASK_ISR_TO_SCHEDULER (1 << SYSVIEW_EVTID_ISR_TO_SCHEDULER) +#define SYSVIEW_EVTMASK_TIMER_ENTER (1 << SYSVIEW_EVTID_TIMER_ENTER) +#define SYSVIEW_EVTMASK_TIMER_EXIT (1 << SYSVIEW_EVTID_TIMER_EXIT) +#define SYSVIEW_EVTMASK_STACK_INFO (1 << SYSVIEW_EVTID_STACK_INFO) +#define SYSVIEW_EVTMASK_MODULEDESC (1 << SYSVIEW_EVTID_MODULEDESC) + +#define SYSVIEW_EVTMASK_INIT (1 << SYSVIEW_EVTID_INIT) +#define SYSVIEW_EVTMASK_NAME_RESOURCE (1 << SYSVIEW_EVTID_NAME_RESOURCE) +#define SYSVIEW_EVTMASK_PRINT_FORMATTED (1 << SYSVIEW_EVTID_PRINT_FORMATTED) +#define SYSVIEW_EVTMASK_NUMMODULES (1 << SYSVIEW_EVTID_NUMMODULES) +#define SYSVIEW_EVTMASK_END_CALL (1 << SYSVIEW_EVTID_END_CALL) +#define SYSVIEW_EVTMASK_TASK_TERMINATE (1 << SYSVIEW_EVTID_TASK_TERMINATE) + +#define SYSVIEW_EVTMASK_EX (1 << SYSVIEW_EVTID_EX) + +#define SYSVIEW_EVTMASK_ALL_INTERRUPTS ( SYSVIEW_EVTMASK_ISR_ENTER \ + | SYSVIEW_EVTMASK_ISR_EXIT \ + | SYSVIEW_EVTMASK_ISR_TO_SCHEDULER) +#define SYSVIEW_EVTMASK_ALL_TASKS ( SYSVIEW_EVTMASK_TASK_START_EXEC \ + | SYSVIEW_EVTMASK_TASK_STOP_EXEC \ + | SYSVIEW_EVTMASK_TASK_START_READY \ + | SYSVIEW_EVTMASK_TASK_STOP_READY \ + | SYSVIEW_EVTMASK_TASK_CREATE \ + | SYSVIEW_EVTMASK_TASK_INFO \ + | SYSVIEW_EVTMASK_STACK_INFO \ + | SYSVIEW_EVTMASK_TASK_TERMINATE) + +/********************************************************************* +* +* Structures +* +********************************************************************** +*/ + +typedef struct { + U32 TaskID; + const char* sName; + U32 Prio; + U32 StackBase; + U32 StackSize; +} SEGGER_SYSVIEW_TASKINFO; + +typedef struct SEGGER_SYSVIEW_MODULE_STRUCT SEGGER_SYSVIEW_MODULE; + +struct SEGGER_SYSVIEW_MODULE_STRUCT { + const char* sModule; + U32 NumEvents; + U32 EventOffset; + void (*pfSendModuleDesc)(void); + SEGGER_SYSVIEW_MODULE* pNext; +}; + +typedef void (SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC)(void); + + +/********************************************************************* +* +* Global data +* +********************************************************************** +*/ + +#ifdef EXTERN + #undef EXTERN +#endif + +#ifndef SEGGER_SYSVIEW_C // Defined in SEGGER_SYSVIEW.c which includes this header beside other C-files + #define EXTERN extern +#else + #define EXTERN +#endif + +EXTERN unsigned int SEGGER_SYSVIEW_TickCnt; +EXTERN unsigned int SEGGER_SYSVIEW_InterruptId; + +#undef EXTERN + +/********************************************************************* +* +* API functions +* +********************************************************************** +*/ + +typedef struct { + U64 (*pfGetTime) (void); + void (*pfSendTaskList) (void); +} SEGGER_SYSVIEW_OS_API; + +/********************************************************************* +* +* Control and initialization functions +*/ +void SEGGER_SYSVIEW_Init (U32 SysFreq, U32 CPUFreq, const SEGGER_SYSVIEW_OS_API *pOSAPI, SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC pfSendSysDesc); +void SEGGER_SYSVIEW_SetRAMBase (U32 RAMBaseAddress); +void SEGGER_SYSVIEW_Start (void); +void SEGGER_SYSVIEW_Stop (void); +void SEGGER_SYSVIEW_GetSysDesc (void); +void SEGGER_SYSVIEW_SendTaskList (void); +void SEGGER_SYSVIEW_SendTaskInfo (const SEGGER_SYSVIEW_TASKINFO* pInfo); +void SEGGER_SYSVIEW_SendSysDesc (const char* sSysDesc); +int SEGGER_SYSVIEW_IsStarted (void); +int SEGGER_SYSVIEW_GetChannelID (void); + +/********************************************************************* +* +* Event recording functions +*/ +void SEGGER_SYSVIEW_RecordVoid (unsigned int EventId); +void SEGGER_SYSVIEW_RecordU32 (unsigned int EventId, U32 Para0); +void SEGGER_SYSVIEW_RecordU32x2 (unsigned int EventId, U32 Para0, U32 Para1); +void SEGGER_SYSVIEW_RecordU32x3 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2); +void SEGGER_SYSVIEW_RecordU32x4 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3); +void SEGGER_SYSVIEW_RecordU32x5 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4); +void SEGGER_SYSVIEW_RecordU32x6 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5); +void SEGGER_SYSVIEW_RecordU32x7 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6); +void SEGGER_SYSVIEW_RecordU32x8 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7); +void SEGGER_SYSVIEW_RecordU32x9 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7, U32 Para8); +void SEGGER_SYSVIEW_RecordU32x10 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7, U32 Para8, U32 Para9); +void SEGGER_SYSVIEW_RecordString (unsigned int EventId, const char* pString); +void SEGGER_SYSVIEW_RecordSystime (void); +void SEGGER_SYSVIEW_RecordEnterISR (void); +void SEGGER_SYSVIEW_RecordExitISR (void); +void SEGGER_SYSVIEW_RecordExitISRToScheduler (void); +void SEGGER_SYSVIEW_RecordEnterTimer (U32 TimerId); +void SEGGER_SYSVIEW_RecordExitTimer (void); +void SEGGER_SYSVIEW_RecordEndCall (unsigned int EventID); +void SEGGER_SYSVIEW_RecordEndCallU32 (unsigned int EventID, U32 Para0); + +void SEGGER_SYSVIEW_OnIdle (void); +void SEGGER_SYSVIEW_OnTaskCreate (U32 TaskId); +void SEGGER_SYSVIEW_OnTaskTerminate (U32 TaskId); +void SEGGER_SYSVIEW_OnTaskStartExec (U32 TaskId); +void SEGGER_SYSVIEW_OnTaskStopExec (void); +void SEGGER_SYSVIEW_OnTaskStartReady (U32 TaskId); +void SEGGER_SYSVIEW_OnTaskStopReady (U32 TaskId, unsigned int Cause); +void SEGGER_SYSVIEW_MarkStart (unsigned int MarkerId); +void SEGGER_SYSVIEW_MarkStop (unsigned int MarkerId); +void SEGGER_SYSVIEW_Mark (unsigned int MarkerId); +void SEGGER_SYSVIEW_NameMarker (unsigned int MarkerId, const char* sName); + +void SEGGER_SYSVIEW_NameResource (U32 ResourceId, const char* sName); + +int SEGGER_SYSVIEW_SendPacket (U8* pPacket, U8* pPayloadEnd, unsigned int EventId); + +/********************************************************************* +* +* Event parameter encoding functions +*/ +U8* SEGGER_SYSVIEW_EncodeU32 (U8* pPayload, U32 Value); +U8* SEGGER_SYSVIEW_EncodeData (U8* pPayload, const char* pSrc, unsigned int Len); +U8* SEGGER_SYSVIEW_EncodeString (U8* pPayload, const char* s, unsigned int MaxLen); +U8* SEGGER_SYSVIEW_EncodeId (U8* pPayload, U32 Id); +U32 SEGGER_SYSVIEW_ShrinkId (U32 Id); + + +/********************************************************************* +* +* Middleware module registration +*/ +void SEGGER_SYSVIEW_RegisterModule (SEGGER_SYSVIEW_MODULE* pModule); +void SEGGER_SYSVIEW_RecordModuleDescription (const SEGGER_SYSVIEW_MODULE* pModule, const char* sDescription); +void SEGGER_SYSVIEW_SendModule (U8 ModuleId); +void SEGGER_SYSVIEW_SendModuleDescription (void); +void SEGGER_SYSVIEW_SendNumModules (void); + +/********************************************************************* +* +* printf-Style functions +*/ +#ifndef SEGGER_SYSVIEW_EXCLUDE_PRINTF // Define in project to avoid warnings about variable parameter list +void SEGGER_SYSVIEW_PrintfHostEx (const char* s, U32 Options, ...); +void SEGGER_SYSVIEW_PrintfTargetEx (const char* s, U32 Options, ...); +void SEGGER_SYSVIEW_PrintfHost (const char* s, ...); +void SEGGER_SYSVIEW_PrintfTarget (const char* s, ...); +void SEGGER_SYSVIEW_WarnfHost (const char* s, ...); +void SEGGER_SYSVIEW_WarnfTarget (const char* s, ...); +void SEGGER_SYSVIEW_ErrorfHost (const char* s, ...); +void SEGGER_SYSVIEW_ErrorfTarget (const char* s, ...); +#endif + +void SEGGER_SYSVIEW_Print (const char* s); +void SEGGER_SYSVIEW_Warn (const char* s); +void SEGGER_SYSVIEW_Error (const char* s); + +/********************************************************************* +* +* Run-time configuration functions +*/ +void SEGGER_SYSVIEW_EnableEvents (U32 EnableMask); +void SEGGER_SYSVIEW_DisableEvents (U32 DisableMask); + +/********************************************************************* +* +* Application-provided functions +*/ +void SEGGER_SYSVIEW_Conf (void); +U32 SEGGER_SYSVIEW_X_GetTimestamp (void); +U32 SEGGER_SYSVIEW_X_GetInterruptId (void); + +void SEGGER_SYSVIEW_X_StartComm (void); +void SEGGER_SYSVIEW_X_OnEventRecorded (unsigned NumBytes); + +#ifdef __cplusplus +} +#endif + +/********************************************************************* +* +* Compatibility API defines +*/ +#define SEGGER_SYSVIEW_OnUserStart SEGGER_SYSVIEW_MarkStart +#define SEGGER_SYSVIEW_OnUserStop SEGGER_SYSVIEW_MarkStop + +#endif + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_SYSVIEW_ConfDefaults.h b/bsp/projects/common/segger/SEGGER_SYSVIEW_ConfDefaults.h new file mode 100644 index 0000000..91dc85f --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_SYSVIEW_ConfDefaults.h @@ -0,0 +1,579 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +-------------------------- END-OF-HEADER ----------------------------- +File : SEGGER_SYSVIEW_ConfDefaults.h +Purpose : Defines defaults for configurable defines used in + SEGGER SystemView. +Revision: $Rev: 26230 $ +*/ + +#ifndef SEGGER_SYSVIEW_CONFDEFAULTS_H +#define SEGGER_SYSVIEW_CONFDEFAULTS_H + +/********************************************************************* +* +* #include Section +* +********************************************************************** +*/ + +#include "SEGGER_SYSVIEW_Conf.h" +#include "SEGGER_RTT_Conf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ +// +// Use auto-detection for SEGGER_SYSVIEW_CORE define +// based on compiler-/toolchain-specific defines +// to define SEGGER_SYSVIEW_GET_INTERRUPT_ID and SEGGER_SYSVIEW_GET_TIMESTAMP +// +#define SEGGER_SYSVIEW_CORE_OTHER 0 +#define SEGGER_SYSVIEW_CORE_CM0 1 // Cortex-M0/M0+/M1 +#define SEGGER_SYSVIEW_CORE_CM3 2 // Cortex-M3/M4/M7 +#define SEGGER_SYSVIEW_CORE_RX 3 // Renesas RX +#ifndef SEGGER_SYSVIEW_CORE + #if (defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __SEGGER_CC__) || (defined __GNUC__) || (defined __clang__) + #if (defined __ARM_ARCH_6M__) || (defined __ARM_ARCH_8M_BASE__) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0 + #elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3 + #endif + #elif defined(__ICCARM__) + #if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) \ + || (defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__)) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0 + #elif (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) \ + || (defined (__ARM7M__) && (__CORE__ == __ARM7M__)) \ + || (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) \ + || (defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3 + #endif + #elif defined(__CC_ARM) + #if (defined(__TARGET_ARCH_6S_M)) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0 + #elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M)) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3 + #endif + #elif defined(__TI_ARM__) + #ifdef __TI_ARM_V6M0__ + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0 + #elif (defined(__TI_ARM_V7M3__) || defined(__TI_ARM_V7M4__)) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3 + #endif + #elif defined(__ICCRX__) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_RX + #elif defined(__RX) + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_RX + #endif + + #ifndef SEGGER_SYSVIEW_CORE + #define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_OTHER + #endif +#endif + + +/********************************************************************* +* +* Defines, defaults +* +********************************************************************** +*/ +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_APP_NAME +* +* Description +* The application name to be displayed in SystemView. +* Default +* "SystemView-enabled Application" +* Notes +* Convenience define to be used for SEGGER_SYSVIEW_SendSysDesc(). +*/ +#ifndef SEGGER_SYSVIEW_APP_NAME + #define SEGGER_SYSVIEW_APP_NAME "SystemView-enabled Application" +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_DEVICE_NAME +* +* Description +* The target device name to be displayed in SystemView. +* Default +* "undefined device" +* Notes +* Convenience define to be used for SEGGER_SYSVIEW_SendSysDesc(). +*/ +#ifndef SEGGER_SYSVIEW_DEVICE_NAME + #define SEGGER_SYSVIEW_DEVICE_NAME "undefined device" +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_GET_INTERRUPT_ID() +* +* Description +* Function macro to retrieve the Id of the currently active +* interrupt. +* Default +* Call user-supplied function SEGGER_SYSVIEW_X_GetInterruptId(). +* Notes +* For some known compilers and cores, a ready-to-use, core-specific +* default is set. +* ARMv7M: Read ICSR[8:0] (active vector) +* ARMv6M: Read ICSR[5:0] (active vector) +*/ +#ifndef SEGGER_SYSVIEW_GET_INTERRUPT_ID + #if SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM3 + #define SEGGER_SYSVIEW_GET_INTERRUPT_ID() ((*(U32*)(0xE000ED04)) & 0x1FF) // Get the currently active interrupt Id. (i.e. read Cortex-M ICSR[8:0] = active vector) + #elif SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM0 + #if defined(__ICCARM__) + #if (__VER__ > 6010000) + #define SEGGER_SYSVIEW_GET_INTERRUPT_ID() (__get_IPSR()) // Workaround for IAR, which might do a byte-access to 0xE000ED04. Read IPSR instead. + #else + #define SEGGER_SYSVIEW_GET_INTERRUPT_ID() ((*(U32*)(0xE000ED04)) & 0x3F) // Older versions of IAR do not include __get_IPSR, but might also not optimize to byte-access. + #endif + #else + #define SEGGER_SYSVIEW_GET_INTERRUPT_ID() ((*(U32*)(0xE000ED04)) & 0x3F) // Get the currently active interrupt Id. (i.e. read Cortex-M ICSR[5:0] = active vector) + #endif + #else + #define SEGGER_SYSVIEW_GET_INTERRUPT_ID() SEGGER_SYSVIEW_X_GetInterruptId() // Get the currently active interrupt Id from the user-provided function. + #endif +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_GET_TIMESTAMP() +* +* Description +* Function macro to retrieve a system timestamp for SYSVIEW events. +* Default +* Call user-supplied function SEGGER_SYSVIEW_X_GetTimestamp(). +* Notes +* For some known compilers and cores, a ready-to-use, core-specific +* default is set. +* ARMv7M: Read Cortex-M Cycle Count register. +* +* The system timestamp clock frequency has to be passed in +* SEGGER_SYSVIEW_Init(). +*/ +#ifndef SEGGER_SYSVIEW_GET_TIMESTAMP + #if defined (SEGGER_SYSVIEW_CORE) && (SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM3) + #define SEGGER_SYSVIEW_GET_TIMESTAMP() (*(U32 *)(0xE0001004)) // Retrieve a system timestamp. Cortex-M cycle counter. + #else + #define SEGGER_SYSVIEW_GET_TIMESTAMP() SEGGER_SYSVIEW_X_GetTimestamp() // Retrieve a system timestamp via user-defined function + #endif +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_TIMESTAMP_BITS +* +* Description +* Number of valid (low-order) bits delivered in system timestamp. +* Default +* 32 +* Notes +* Value has to match system timestamp clock source. +*/ +// Define number of valid bits low-order delivered by clock source. +#ifndef SEGGER_SYSVIEW_TIMESTAMP_BITS + #define SEGGER_SYSVIEW_TIMESTAMP_BITS 32 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_RTT_CHANNEL +* +* Description +* The RTT channel that SystemView will use. +* Default +* 0: Auto selection. +* Notes +* Value has to be lower than SEGGER_RTT_MAX_NUM_UP_BUFFERS. +*/ +#ifndef SEGGER_SYSVIEW_RTT_CHANNEL + #define SEGGER_SYSVIEW_RTT_CHANNEL 0 +#endif +// Sanity check of RTT channel +#if (SEGGER_SYSVIEW_RTT_CHANNEL == 0) && (SEGGER_RTT_MAX_NUM_UP_BUFFERS < 2) + #error "SEGGER_RTT_MAX_NUM_UP_BUFFERS in SEGGER_RTT_Conf.h has to be > 1!" +#elif (SEGGER_SYSVIEW_RTT_CHANNEL >= SEGGER_RTT_MAX_NUM_UP_BUFFERS) + #error "SEGGER_RTT_MAX_NUM_UP_BUFFERS in SEGGER_RTT_Conf.h has to be > SEGGER_SYSVIEW_RTT_CHANNEL!" +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_RTT_BUFFER_SIZE +* +* Description +* Number of bytes that SystemView uses for the RTT buffer. +* Default +* 1024 +*/ +#ifndef SEGGER_SYSVIEW_RTT_BUFFER_SIZE + #define SEGGER_SYSVIEW_RTT_BUFFER_SIZE 1024 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_SECTION +* +* Description +* Section to place the SystemView RTT Buffer into. +* Default +* undefined: Do not place into a specific section. +* Notes +* If SEGGER_RTT_SECTION is defined, the default changes to use +* this section for the SystemView RTT Buffer, too. +*/ +#if !(defined SEGGER_SYSVIEW_SECTION) && (defined SEGGER_RTT_SECTION) + #define SEGGER_SYSVIEW_SECTION SEGGER_RTT_SECTION +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE +* +* Description +* Largest cache line size (in bytes) in the target system. +* Default +* 0 +* Notes +* Required in systems with caches to make sure that the SystemView +* RTT buffer can be aligned accordingly. +*/ +#ifndef SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE + #define SEGGER_SYSVIEW_CPU_CACHE_LINE_SIZE 0 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_ID_BASE +* +* Description +* Lowest Id reported by the application. +* Default +* 0 +* Notes +* Value is usually subtracted from mailboxes, semaphores, tasks, +* .... addresses, to compress event parameters. +* Should be the lowest RAM address of the system. +*/ +#ifndef SEGGER_SYSVIEW_ID_BASE + #define SEGGER_SYSVIEW_ID_BASE 0 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_ID_SHIFT +* +* Description +* Number of bits to shift Ids. +* Default +* 0 +* Notes +* Ids are shifted to compress event parameters. +* Should match the alignment of Ids (addresses), +* e.g. 2 when Ids are 4 byte aligned. +*/ +#ifndef SEGGER_SYSVIEW_ID_SHIFT + #define SEGGER_SYSVIEW_ID_SHIFT 0 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_MAX_ARGUMENTS +* +* Description +* Maximum number of arguments which are handled with SystemView +* print routines or may be encoded in one recording function. +* routines. +* Default +* 16 +*/ +#ifndef SEGGER_SYSVIEW_MAX_ARGUMENTS + #define SEGGER_SYSVIEW_MAX_ARGUMENTS 16 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_MAX_STRING_LEN +* +* Description +* Maximum string length which can be used in SystemView print and +* system description routines. +* Default +* 128 +*/ +#ifndef SEGGER_SYSVIEW_MAX_STRING_LEN + #define SEGGER_SYSVIEW_MAX_STRING_LEN 128 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_SUPPORT_LONG_ID +* +* Description +* It set, support enconding Evend Ids longer than 14 bit. +* Default +* 1 +*/ +#ifndef SEGGER_SYSVIEW_SUPPORT_LONG_ID + #define SEGGER_SYSVIEW_SUPPORT_LONG_ID 1 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_SUPPORT_LONG_DATA +* +* Description +* It set, support enconding event data longer than 14 bit. +* Default +* 0 +*/ +#ifndef SEGGER_SYSVIEW_SUPPORT_LONG_DATA + #define SEGGER_SYSVIEW_SUPPORT_LONG_DATA 0 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT +* +* Description +* If enabled, on SEGGER_SYSVIEW_PrintHost, check the format string +* and if it includes unsupported formatters, use formatting on the +* target instead. +* Default +* 0: Disabled. +*/ +#ifndef SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT + #define SEGGER_SYSVIEW_PRINTF_IMPLICIT_FORMAT 0 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_USE_INTERNAL_RECORDER +* +* Description +* If set, an internal recorder, such as UART or IP is used. +* Default +* 0: Disabled. +* Notes +* Convenience define to be used by SEGGER_SYSVIEW_Conf(), +* such as in embOS configuration to enable Cortex-M cycle counter. +*/ +#ifndef SEGGER_SYSVIEW_USE_INTERNAL_RECORDER + #define SEGGER_SYSVIEW_USE_INTERNAL_RECORDER 0 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_CAN_RESTART +* +* Description +* If enabled, send the SystemView start sequence on every start +* command, not just on the first one. +* Enables restart when SystemView disconnected unexpectedly. +* Default +* 1: Enabled +*/ +#ifndef SEGGER_SYSVIEW_CAN_RESTART + #define SEGGER_SYSVIEW_CAN_RESTART 1 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_START_ON_INIT +* +* Description +* Enable calling SEGGER_SYSVIEW_Start() after initialization. +* Default +* 0: Disabled. +* Notes +* Convenience define to be used by SEGGER_SYSVIEW_Conf(), +* such as in embOS configuration. +*/ +#ifndef SEGGER_SYSVIEW_START_ON_INIT + #define SEGGER_SYSVIEW_START_ON_INIT 0 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_USE_STATIC_BUFFER +* +* Description +* If enabled, use a static buffer instead of a buffer on the stack +* for SystemView event packets. +* Default +* 1: Enabled. +* Notes +* If enabled, the static memory use by SystemView is increased by +* the maximum packet size. SystemView is locked on entry of a +* recording function. +* If disabled, the stack usage by SystemView recording functions +* might be increased by up to the maximum packet size. SystemView +* is locked when writing the packet to the RTT buffer. +*/ +#ifndef SEGGER_SYSVIEW_USE_STATIC_BUFFER + #define SEGGER_SYSVIEW_USE_STATIC_BUFFER 1 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_MAX_PACKET_SIZE +* +* Description +* Maximum packet size for a SystemView event. +* Default +* Automatically calculated. +* Notes +* The maximum packet size is mainly defined by the maximum string +* length and the maximum number of arguments. +*/ +#ifndef SEGGER_SYSVIEW_MAX_PACKET_SIZE + #define SEGGER_SYSVIEW_MAX_PACKET_SIZE (SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_MAX_STRING_LEN + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_ARGUMENTS * SEGGER_SYSVIEW_QUANTA_U32) +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_POST_MORTEM_MODE +* +* Description +* If enabled, SystemView records for post-mortem analysis instead +* of real-time analysis. +* Default +* 0: Disabled. +* Notes +* For more information refer to +* https://www.segger.com/products/development-tools/systemview/technology/post-mortem-mode +*/ +#ifndef SEGGER_SYSVIEW_POST_MORTEM_MODE + #define SEGGER_SYSVIEW_POST_MORTEM_MODE 0 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT +* +* Description +* Configure how frequently syncronization is sent in post-mortem +* mode. +* Default +* 8: (1 << 8) = Every 256 Events. +* Notes +* In post-mortem mode, at least one sync has to be in the RTT buffer. +* Recommended sync frequency: Buffer Size / 16 +* For more information refer to +* https://www.segger.com/products/development-tools/systemview/technology/post-mortem-mode +*/ +#ifndef SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT + #define SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT 8 +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_ON_EVENT_RECORDED() +* +* Description +* Function macro to notify recorder about a new event in buffer. +* Default +* undefined: Do not notify recorder. +* Notes +* Used for non-J-Link recorder, +* such as to enable transmission via UART or notify IP task. +*/ +#ifndef SEGGER_SYSVIEW_ON_EVENT_RECORDED + #define SEGGER_SYSVIEW_ON_EVENT_RECORDED(NumBytes) +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_LOCK() +* +* Description +* Function macro to (nestable) lock SystemView recording. +* Default +* Use RTT Locking mechanism (defined by SEGGER_RTT_LOCK()). +* Notes +* If SystemView recording is not locked, recording events from +* interrupts and tasks may lead to unpredictable, undefined, event +* data. +*/ +#ifndef SEGGER_SYSVIEW_LOCK + #define SEGGER_SYSVIEW_LOCK() SEGGER_RTT_LOCK() +#endif + +/********************************************************************* +* +* Define: SEGGER_SYSVIEW_UNLOCK +* +* Description +* Function macro to unlock SystemView recording. +* Default +* Use RTT Unlocking mechanism (defined by SEGGER_RTT_UNLOCK()). +*/ +#ifndef SEGGER_SYSVIEW_UNLOCK + #define SEGGER_SYSVIEW_UNLOCK() SEGGER_RTT_UNLOCK() +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_SYSVIEW_FreeRTOS.c b/bsp/projects/common/segger/SEGGER_SYSVIEW_FreeRTOS.c new file mode 100644 index 0000000..7253466 --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_SYSVIEW_FreeRTOS.c @@ -0,0 +1,252 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +-------------------------- END-OF-HEADER ----------------------------- + +File : SEGGER_SYSVIEW_FreeRTOS.c +Purpose : Interface between FreeRTOS and SystemView. +Revision: $Rev: 7947 $ +*/ +#include "FreeRTOS.h" +#include "task.h" +#include "SEGGER_SYSVIEW.h" +#include "SEGGER_SYSVIEW_FreeRTOS.h" +#include "string.h" // Required for memset + + + +typedef struct SYSVIEW_FREERTOS_TASK_STATUS SYSVIEW_FREERTOS_TASK_STATUS; + +struct SYSVIEW_FREERTOS_TASK_STATUS { + U32 xHandle; + const char* pcTaskName; + unsigned uxCurrentPriority; + U32 pxStack; + unsigned uStackHighWaterMark; +}; + +static SYSVIEW_FREERTOS_TASK_STATUS _aTasks[SYSVIEW_FREERTOS_MAX_NOF_TASKS]; +static unsigned _NumTasks; + +/********************************************************************* +* +* _cbSendTaskList() +* +* Function description +* This function is part of the link between FreeRTOS and SYSVIEW. +* Called from SystemView when asked by the host, it uses SYSVIEW +* functions to send the entire task list to the host. +*/ +static void _cbSendTaskList(void) { + unsigned n; + + for (n = 0; n < _NumTasks; n++) { +#if INCLUDE_uxTaskGetStackHighWaterMark // Report Task Stack High Watermark + _aTasks[n].uStackHighWaterMark = uxTaskGetStackHighWaterMark((TaskHandle_t)_aTasks[n].xHandle); +#endif + SYSVIEW_SendTaskInfo((U32)_aTasks[n].xHandle, _aTasks[n].pcTaskName, (unsigned)_aTasks[n].uxCurrentPriority, (U32)_aTasks[n].pxStack, (unsigned)_aTasks[n].uStackHighWaterMark); + } +} + +/********************************************************************* +* +* _cbGetTime() +* +* Function description +* This function is part of the link between FreeRTOS and SYSVIEW. +* Called from SystemView when asked by the host, returns the +* current system time in micro seconds. +*/ +static U64 _cbGetTime(void) { + U64 Time; + + Time = xTaskGetTickCountFromISR(); + Time *= portTICK_PERIOD_MS; + Time *= 1000; + return Time; +} + +/********************************************************************* +* +* Global functions +* +********************************************************************** +*/ +/********************************************************************* +* +* SYSVIEW_AddTask() +* +* Function description +* Add a task to the internal list and record its information. +*/ +void SYSVIEW_AddTask(U32 xHandle, const char* pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark) { + + if (memcmp(pcTaskName, "IDLE", 5) == 0) { + return; + } + + if (_NumTasks >= SYSVIEW_FREERTOS_MAX_NOF_TASKS) { + SEGGER_SYSVIEW_Warn("SYSTEMVIEW: Could not record task information. Maximum number of tasks reached."); + return; + } + + _aTasks[_NumTasks].xHandle = xHandle; + _aTasks[_NumTasks].pcTaskName = pcTaskName; + _aTasks[_NumTasks].uxCurrentPriority = uxCurrentPriority; + _aTasks[_NumTasks].pxStack = pxStack; + _aTasks[_NumTasks].uStackHighWaterMark = uStackHighWaterMark; + + _NumTasks++; + + SYSVIEW_SendTaskInfo(xHandle, pcTaskName,uxCurrentPriority, pxStack, uStackHighWaterMark); + +} + +/********************************************************************* +* +* SYSVIEW_UpdateTask() +* +* Function description +* Update a task in the internal list and record its information. +*/ +void SYSVIEW_UpdateTask(U32 xHandle, const char* pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark) { + unsigned n; + + if (memcmp(pcTaskName, "IDLE", 5) == 0) { + return; + } + + for (n = 0; n < _NumTasks; n++) { + if (_aTasks[n].xHandle == xHandle) { + break; + } + } + if (n < _NumTasks) { + _aTasks[n].pcTaskName = pcTaskName; + _aTasks[n].uxCurrentPriority = uxCurrentPriority; + _aTasks[n].pxStack = pxStack; + _aTasks[n].uStackHighWaterMark = uStackHighWaterMark; + + SYSVIEW_SendTaskInfo(xHandle, pcTaskName, uxCurrentPriority, pxStack, uStackHighWaterMark); + } else { + SYSVIEW_AddTask(xHandle, pcTaskName, uxCurrentPriority, pxStack, uStackHighWaterMark); + } +} + +/********************************************************************* +* +* SYSVIEW_DeleteTask() +* +* Function description +* Delete a task from the internal list. +*/ +void SYSVIEW_DeleteTask(U32 xHandle) { + unsigned n; + + if (_NumTasks == 0) { + return; // Early out + } + for (n = 0; n < _NumTasks; n++) { + if (_aTasks[n].xHandle == xHandle) { + break; + } + } + if (n == (_NumTasks - 1)) { + // + // Task is last item in list. + // Simply zero the item and decrement number of tasks. + // + memset(&_aTasks[n], 0, sizeof(_aTasks[n])); + _NumTasks--; + } else if (n < _NumTasks) { + // + // Task is in the middle of the list. + // Move last item to current position and decrement number of tasks. + // Order of tasks does not really matter, so no need to move all following items. + // + _aTasks[n].xHandle = _aTasks[_NumTasks - 1].xHandle; + _aTasks[n].pcTaskName = _aTasks[_NumTasks - 1].pcTaskName; + _aTasks[n].uxCurrentPriority = _aTasks[_NumTasks - 1].uxCurrentPriority; + _aTasks[n].pxStack = _aTasks[_NumTasks - 1].pxStack; + _aTasks[n].uStackHighWaterMark = _aTasks[_NumTasks - 1].uStackHighWaterMark; + memset(&_aTasks[_NumTasks - 1], 0, sizeof(_aTasks[_NumTasks - 1])); + _NumTasks--; + } +} + +/********************************************************************* +* +* SYSVIEW_SendTaskInfo() +* +* Function description +* Record task information. +*/ +void SYSVIEW_SendTaskInfo(U32 TaskID, const char* sName, unsigned Prio, U32 StackBase, unsigned StackSize) { + SEGGER_SYSVIEW_TASKINFO TaskInfo; + + memset(&TaskInfo, 0, sizeof(TaskInfo)); // Fill all elements with 0 to allow extending the structure in future version without breaking the code + TaskInfo.TaskID = TaskID; + TaskInfo.sName = sName; + TaskInfo.Prio = Prio; + TaskInfo.StackBase = StackBase; + TaskInfo.StackSize = StackSize; + SEGGER_SYSVIEW_SendTaskInfo(&TaskInfo); +} + +/********************************************************************* +* +* Public API structures +* +********************************************************************** +*/ +// Callbacks provided to SYSTEMVIEW by FreeRTOS +const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI = { + _cbGetTime, + _cbSendTaskList, +}; + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_SYSVIEW_FreeRTOS.h b/bsp/projects/common/segger/SEGGER_SYSVIEW_FreeRTOS.h new file mode 100644 index 0000000..db44283 --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_SYSVIEW_FreeRTOS.h @@ -0,0 +1,334 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +-------------------------- END-OF-HEADER ----------------------------- + +File : SEGGER_SYSVIEW_FreeRTOS.h +Purpose : Interface between FreeRTOS and SystemView. + Tested with FreeRTOS V10.4.3 +Revision: $Rev: 7745 $ + +Notes: + (1) Include this file at the end of FreeRTOSConfig.h +*/ + +#ifndef SYSVIEW_FREERTOS_H +#define SYSVIEW_FREERTOS_H + +#include "SEGGER_SYSVIEW.h" + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ +#ifndef portSTACK_GROWTH + #define portSTACK_GROWTH ( -1 ) +#endif + +#define SYSVIEW_FREERTOS_MAX_NOF_TASKS 16 + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ +#define apiID_OFFSET (32u) + +#define apiID_VTASKALLOCATEMPUREGIONS (1u) +#define apiID_VTASKDELETE (2u) +#define apiID_VTASKDELAY (3u) +#define apiID_VTASKDELAYUNTIL (4u) +#define apiID_UXTASKPRIORITYGET (5u) +#define apiID_UXTASKPRIORITYGETFROMISR (6u) +#define apiID_ETASKGETSTATE (7u) +#define apiID_VTASKPRIORITYSET (8u) +#define apiID_VTASKSUSPEND (9u) +#define apiID_VTASKRESUME (10u) +#define apiID_XTASKRESUMEFROMISR (11u) +#define apiID_VTASKSTARTSCHEDULER (12u) +#define apiID_VTASKENDSCHEDULER (13u) +#define apiID_VTASKSUSPENDALL (14u) +#define apiID_XTASKRESUMEALL (15u) +#define apiID_XTASKGETTICKCOUNT (16u) +#define apiID_XTASKGETTICKCOUNTFROMISR (17u) +#define apiID_UXTASKGETNUMBEROFTASKS (18u) +#define apiID_PCTASKGETTASKNAME (19u) +#define apiID_UXTASKGETSTACKHIGHWATERMARK (20u) +#define apiID_VTASKSETAPPLICATIONTASKTAG (21u) +#define apiID_XTASKGETAPPLICATIONTASKTAG (22u) +#define apiID_VTASKSETTHREADLOCALSTORAGEPOINTER (23u) +#define apiID_PVTASKGETTHREADLOCALSTORAGEPOINTER (24u) +#define apiID_XTASKCALLAPPLICATIONTASKHOOK (25u) +#define apiID_XTASKGETIDLETASKHANDLE (26u) +#define apiID_UXTASKGETSYSTEMSTATE (27u) +#define apiID_VTASKLIST (28u) +#define apiID_VTASKGETRUNTIMESTATS (29u) +#define apiID_XTASKGENERICNOTIFY (30u) +#define apiID_XTASKGENERICNOTIFYFROMISR (31u) +#define apiID_XTASKNOTIFYWAIT (32u) +#define apiID_VTASKNOTIFYGIVEFROMISR (33u) +#define apiID_ULTASKNOTIFYTAKE (34u) +#define apiID_XTASKNOTIFYSTATECLEAR (35u) +#define apiID_XTASKGETCURRENTTASKHANDLE (36u) +#define apiID_VTASKSETTIMEOUTSTATE (37u) +#define apiID_XTASKCHECKFORTIMEOUT (38u) +#define apiID_VTASKMISSEDYIELD (39u) +#define apiID_XTASKGETSCHEDULERSTATE (40u) +#define apiID_VTASKPRIORITYINHERIT (41u) +#define apiID_XTASKPRIORITYDISINHERIT (42u) +#define apiID_XTASKGENERICCREATE (43u) +#define apiID_UXTASKGETTASKNUMBER (44u) +#define apiID_VTASKSETTASKNUMBER (45u) +#define apiID_VTASKSTEPTICK (46u) +#define apiID_ETASKCONFIRMSLEEPMODESTATUS (47u) +#define apiID_XTIMERCREATE (48u) +#define apiID_PVTIMERGETTIMERID (49u) +#define apiID_VTIMERSETTIMERID (50u) +#define apiID_XTIMERISTIMERACTIVE (51u) +#define apiID_XTIMERGETTIMERDAEMONTASKHANDLE (52u) +#define apiID_XTIMERPENDFUNCTIONCALLFROMISR (53u) +#define apiID_XTIMERPENDFUNCTIONCALL (54u) +#define apiID_PCTIMERGETTIMERNAME (55u) +#define apiID_XTIMERCREATETIMERTASK (56u) +#define apiID_XTIMERGENERICCOMMAND (57u) +#define apiID_XQUEUEGENERICSEND (58u) +#define apiID_XQUEUEPEEKFROMISR (59u) +#define apiID_XQUEUEGENERICRECEIVE (60u) +#define apiID_UXQUEUEMESSAGESWAITING (61u) +#define apiID_UXQUEUESPACESAVAILABLE (62u) +#define apiID_VQUEUEDELETE (63u) +#define apiID_XQUEUEGENERICSENDFROMISR (64u) +#define apiID_XQUEUEGIVEFROMISR (65u) +#define apiID_XQUEUERECEIVEFROMISR (66u) +#define apiID_XQUEUEISQUEUEEMPTYFROMISR (67u) +#define apiID_XQUEUEISQUEUEFULLFROMISR (68u) +#define apiID_UXQUEUEMESSAGESWAITINGFROMISR (69u) +#define apiID_XQUEUEALTGENERICSEND (70u) +#define apiID_XQUEUEALTGENERICRECEIVE (71u) +#define apiID_XQUEUECRSENDFROMISR (72u) +#define apiID_XQUEUECRRECEIVEFROMISR (73u) +#define apiID_XQUEUECRSEND (74u) +#define apiID_XQUEUECRRECEIVE (75u) +#define apiID_XQUEUECREATEMUTEX (76u) +#define apiID_XQUEUECREATECOUNTINGSEMAPHORE (77u) +#define apiID_XQUEUEGETMUTEXHOLDER (78u) +#define apiID_XQUEUETAKEMUTEXRECURSIVE (79u) +#define apiID_XQUEUEGIVEMUTEXRECURSIVE (80u) +#define apiID_VQUEUEADDTOREGISTRY (81u) +#define apiID_VQUEUEUNREGISTERQUEUE (82u) +#define apiID_XQUEUEGENERICCREATE (83u) +#define apiID_XQUEUECREATESET (84u) +#define apiID_XQUEUEADDTOSET (85u) +#define apiID_XQUEUEREMOVEFROMSET (86u) +#define apiID_XQUEUESELECTFROMSET (87u) +#define apiID_XQUEUESELECTFROMSETFROMISR (88u) +#define apiID_XQUEUEGENERICRESET (89u) +#define apiID_VLISTINITIALISE (90u) +#define apiID_VLISTINITIALISEITEM (91u) +#define apiID_VLISTINSERT (92u) +#define apiID_VLISTINSERTEND (93u) +#define apiID_UXLISTREMOVE (94u) +#define apiID_XEVENTGROUPCREATE (95u) +#define apiID_XEVENTGROUPWAITBITS (96u) +#define apiID_XEVENTGROUPCLEARBITS (97u) +#define apiID_XEVENTGROUPCLEARBITSFROMISR (98u) +#define apiID_XEVENTGROUPSETBITS (99u) +#define apiID_XEVENTGROUPSETBITSFROMISR (100u) +#define apiID_XEVENTGROUPSYNC (101u) +#define apiID_XEVENTGROUPGETBITSFROMISR (102u) +#define apiID_VEVENTGROUPDELETE (103u) +#define apiID_UXEVENTGROUPGETNUMBER (104u) +#define apiID_XSTREAMBUFFERCREATE (105u) +#define apiID_VSTREAMBUFFERDELETE (106u) +#define apiID_XSTREAMBUFFERRESET (107u) +#define apiID_XSTREAMBUFFERSEND (108u) +#define apiID_XSTREAMBUFFERSENDFROMISR (109u) +#define apiID_XSTREAMBUFFERRECEIVE (110u) +#define apiID_XSTREAMBUFFERRECEIVEFROMISR (111u) + +#define traceSTART() SEGGER_SYSVIEW_Conf() + +#define traceTASK_NOTIFY_TAKE(uxIndexToWait) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_ULTASKNOTIFYTAKE, xClearCountOnExit, xTicksToWait) +#define traceTASK_DELAY() SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_VTASKDELAY, xTicksToDelay) +#define traceTASK_DELAY_UNTIL(xTimeToWake) SEGGER_SYSVIEW_RecordVoid (apiID_OFFSET + apiID_VTASKDELAYUNTIL) +#define traceTASK_NOTIFY_GIVE_FROM_ISR(uxIndexToNotify) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_VTASKNOTIFYGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), (U32)pxHigherPriorityTaskWoken) + +#define traceTASK_PRIORITY_INHERIT( pxTCB, uxPriority ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_VTASKPRIORITYINHERIT, (U32)pxMutexHolder) +#define traceTASK_RESUME( pxTCB ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_VTASKRESUME, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB)) +#define traceINCREASE_TICK_COUNT( xTicksToJump ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_VTASKSTEPTICK, xTicksToJump) +#define traceTASK_SUSPEND( pxTCB ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_VTASKSUSPEND, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB)) +#define traceTASK_PRIORITY_DISINHERIT( pxTCB, uxBasePriority ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_XTASKPRIORITYDISINHERIT, (U32)pxMutexHolder) +#define traceTASK_RESUME_FROM_ISR( pxTCB ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_XTASKRESUMEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB)) +#define traceTASK_NOTIFY(uxIndexToNotify) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XTASKGENERICNOTIFY, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue) +#define traceTASK_NOTIFY_FROM_ISR(uxIndexToWait) SEGGER_SYSVIEW_RecordU32x5(apiID_OFFSET + apiID_XTASKGENERICNOTIFYFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue, (U32)pxHigherPriorityTaskWoken) +#define traceTASK_NOTIFY_WAIT(uxIndexToWait) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XTASKNOTIFYWAIT, ulBitsToClearOnEntry, ulBitsToClearOnExit, (U32)pulNotificationValue, xTicksToWait) + +#define traceQUEUE_CREATE( pxNewQueue ) SEGGER_SYSVIEW_RecordU32x3(apiID_OFFSET + apiID_XQUEUEGENERICCREATE, uxQueueLength, uxItemSize, ucQueueType) +#define traceQUEUE_DELETE( pxQueue ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_VQUEUEDELETE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue)) +#define traceQUEUE_PEEK( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), xTicksToWait, 1) +#define traceQUEUE_PEEK_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XQUEUEPEEKFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer)) +#define traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XQUEUEPEEKFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer)) +#define traceQUEUE_RECEIVE( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)0), xTicksToWait, 1) +#define traceQUEUE_RECEIVE_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)0), xTicksToWait, 1) +#define traceQUEUE_SEMAPHORE_RECEIVE( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)0), xTicksToWait, 0) +#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x3(apiID_OFFSET + apiID_XQUEUERECEIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), (U32)pxHigherPriorityTaskWoken) +#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x3(apiID_OFFSET + apiID_XQUEUERECEIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), (U32)pxHigherPriorityTaskWoken) +#define traceQUEUE_REGISTRY_ADD( xQueue, pcQueueName ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_VQUEUEADDTOREGISTRY, SEGGER_SYSVIEW_ShrinkId((U32)xQueue), (U32)pcQueueName) +#if ( configUSE_QUEUE_SETS != 1 ) + #define traceQUEUE_SEND( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, xTicksToWait, xCopyPosition) +#else + #define traceQUEUE_SEND( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), 0u, 0u, xCopyPosition) +#endif +#define traceQUEUE_SEND_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, xTicksToWait, xCopyPosition) +#define traceQUEUE_SEND_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken) +#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken) +#define traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XSTREAMBUFFERCREATE, (U32)xIsMessageBuffer, (U32)pxStreamBuffer) +#define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XSTREAMBUFFERCREATE, (U32)xIsMessageBuffer, 0u) +#define traceSTREAM_BUFFER_DELETE( xStreamBuffer ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_VSTREAMBUFFERDELETE, (U32)xStreamBuffer) +#define traceSTREAM_BUFFER_RESET( xStreamBuffer ) SEGGER_SYSVIEW_RecordU32 (apiID_OFFSET + apiID_XSTREAMBUFFERRESET, (U32)xStreamBuffer) +#define traceSTREAM_BUFFER_SEND( xStreamBuffer, xBytesSent ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XSTREAMBUFFERSEND, (U32)xStreamBuffer, (U32)xBytesSent) +#define traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XSTREAMBUFFERSEND, (U32)xStreamBuffer, 0u) +#define traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xBytesSent ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XSTREAMBUFFERSENDFROMISR, (U32)xStreamBuffer, (U32)xBytesSent) +#define traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XSTREAMBUFFERRECEIVE, (U32)xStreamBuffer, (U32)xReceivedLength) +#define traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XSTREAMBUFFERRECEIVE, (U32)xStreamBuffer, 0u) +#define traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ) SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET + apiID_XSTREAMBUFFERRECEIVEFROMISR, (U32)xStreamBuffer, (U32)xReceivedLength) + + +#define traceTASK_DELETE( pxTCB ) { \ + SEGGER_SYSVIEW_RecordU32(apiID_OFFSET + apiID_VTASKDELETE, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB)); \ + SYSVIEW_DeleteTask((U32)pxTCB); \ + } + + +#if( portSTACK_GROWTH < 0 ) +#define traceTASK_CREATE(pxNewTCB) if (pxNewTCB != NULL) { \ + SEGGER_SYSVIEW_OnTaskCreate((U32)pxNewTCB); \ + SYSVIEW_AddTask((U32)pxNewTCB, \ + &(pxNewTCB->pcTaskName[0]), \ + pxNewTCB->uxPriority, \ + (U32)pxNewTCB->pxStack, \ + ((U32)pxNewTCB->pxTopOfStack - (U32)pxNewTCB->pxStack) \ + ); \ + } +#else +#define traceTASK_CREATE(pxNewTCB) if (pxNewTCB != NULL) { \ + SEGGER_SYSVIEW_OnTaskCreate((U32)pxNewTCB); \ + SYSVIEW_AddTask((U32)pxNewTCB, \ + &(pxNewTCB->pcTaskName[0]), \ + pxNewTCB->uxPriority, \ + (U32)pxNewTCB->pxStack, \ + (U32)(pxNewTCB->pxStack-pxNewTCB->pxTopOfStack) \ + ); \ + } +#endif +#define traceTASK_PRIORITY_SET(pxTask, uxNewPriority) { \ + SEGGER_SYSVIEW_RecordU32x2(apiID_OFFSET+apiID_VTASKPRIORITYSET, \ + SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), \ + uxNewPriority \ + ); \ + SYSVIEW_UpdateTask((U32)pxTask, \ + &(pxTask->pcTaskName[0]), \ + uxNewPriority, \ + (U32)pxTask->pxStack, \ + 0 \ + ); \ + } +// +// Define INCLUDE_xTaskGetIdleTaskHandle as 1 in FreeRTOSConfig.h to allow identification of Idle state. +// +#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) + #define traceTASK_SWITCHED_IN() if(prvGetTCBFromHandle(NULL) == xIdleTaskHandle) { \ + SEGGER_SYSVIEW_OnIdle(); \ + } else { \ + SEGGER_SYSVIEW_OnTaskStartExec((U32)pxCurrentTCB); \ + } +#else + #define traceTASK_SWITCHED_IN() { \ + if (memcmp(pxCurrentTCB->pcTaskName, "IDLE", 5) != 0) { \ + SEGGER_SYSVIEW_OnTaskStartExec((U32)pxCurrentTCB); \ + } else { \ + SEGGER_SYSVIEW_OnIdle(); \ + } \ + } +#endif + +#define traceMOVED_TASK_TO_READY_STATE(pxTCB) SEGGER_SYSVIEW_OnTaskStartReady((U32)pxTCB) +#define traceREADDED_TASK_TO_READY_STATE(pxTCB) + +#define traceMOVED_TASK_TO_DELAYED_LIST() SEGGER_SYSVIEW_OnTaskStopReady((U32)pxCurrentTCB, (1u << 2)) +#define traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST() SEGGER_SYSVIEW_OnTaskStopReady((U32)pxCurrentTCB, (1u << 2)) +#define traceMOVED_TASK_TO_SUSPENDED_LIST(pxTCB) SEGGER_SYSVIEW_OnTaskStopReady((U32)pxTCB, ((3u << 3) | 3)) + + +#define traceISR_EXIT_TO_SCHEDULER() SEGGER_SYSVIEW_RecordExitISRToScheduler() +#define traceISR_EXIT() SEGGER_SYSVIEW_RecordExitISR() +#define traceISR_ENTER() SEGGER_SYSVIEW_RecordEnterISR() + +/********************************************************************* +* +* API functions +* +********************************************************************** +*/ +#ifdef __cplusplus +extern "C" { +#endif +void SYSVIEW_AddTask (U32 xHandle, const char* pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark); +void SYSVIEW_UpdateTask (U32 xHandle, const char* pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark); +void SYSVIEW_DeleteTask (U32 xHandle); +void SYSVIEW_SendTaskInfo (U32 TaskID, const char* sName, unsigned Prio, U32 StackBase, unsigned StackSize); + +#ifdef __cplusplus +} +#endif + +#endif + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_SYSVIEW_Int.h b/bsp/projects/common/segger/SEGGER_SYSVIEW_Int.h new file mode 100644 index 0000000..9559e63 --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_SYSVIEW_Int.h @@ -0,0 +1,99 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +-------------------------- END-OF-HEADER ----------------------------- +File : SEGGER_SYSVIEW_Int.h +Purpose : SEGGER SystemView internal header. +Revision: $Rev: 21281 $ +*/ + +#ifndef SEGGER_SYSVIEW_INT_H +#define SEGGER_SYSVIEW_INT_H + +/********************************************************************* +* +* #include Section +* +********************************************************************** +*/ + +#include "SEGGER_SYSVIEW.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************************************************************* +* +* Private data types +* +********************************************************************** +*/ +// +// Commands that Host can send to target +// +typedef enum { + SEGGER_SYSVIEW_COMMAND_ID_START = 1, + SEGGER_SYSVIEW_COMMAND_ID_STOP, + SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME, + SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST, + SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC, + SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES, + SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC, + SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT = 127, + // Extended commands: Commands >= 128 have a second parameter + SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE = 128 +} SEGGER_SYSVIEW_COMMAND_ID; + +#ifdef __cplusplus +} +#endif + +#endif + +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/SEGGER_debug_def.h b/bsp/projects/common/segger/SEGGER_debug_def.h new file mode 100644 index 0000000..d7b7d9b --- /dev/null +++ b/bsp/projects/common/segger/SEGGER_debug_def.h @@ -0,0 +1,10 @@ +/* + * Copyright 2022 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define MARKER_SEEKER 0xdead0000 +#define MARKER_SPOT 0xdead0001 +#define MARKER_MP3 0xdead0002 +#define MARKER_OGG 0xdead0003 diff --git a/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_GCC.c b/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_GCC.c new file mode 100644 index 0000000..853692f --- /dev/null +++ b/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_GCC.c @@ -0,0 +1,124 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT_Syscalls_GCC.c +Purpose : Low-level functions for using printf() via RTT in GCC. + To use RTT for printf output, include this file in your + application. +Revision: $Rev: 24316 $ +---------------------------------------------------------------------- +*/ +#if (defined __GNUC__) && !(defined __SES_ARM) && !(defined __CROSSWORKS_ARM) && !(defined __ARMCC_VERSION) && !(defined __CC_ARM) + +#include // required for _write_r +#include "SEGGER_RTT.h" + + +/********************************************************************* +* +* Types +* +********************************************************************** +*/ +// +// If necessary define the _reent struct +// to match the one passed by the used standard library. +// +struct _reent; + +/********************************************************************* +* +* Function prototypes +* +********************************************************************** +*/ +_ssize_t _write (int file, const void *ptr, size_t len); +_ssize_t _write_r(struct _reent *r, int file, const void *ptr, size_t len); + +/********************************************************************* +* +* Global functions +* +********************************************************************** +*/ + +/********************************************************************* +* +* _write() +* +* Function description +* Low-level write function. +* libc subroutines will use this system routine for output to all files, +* including stdout. +* Write data via RTT. +*/ +_ssize_t _write(int file, const void *ptr, size_t len) { + (void) file; /* Not used, avoid warning */ + SEGGER_RTT_Write(0, ptr, len); + return len; +} + +/********************************************************************* +* +* _write_r() +* +* Function description +* Low-level reentrant write function. +* libc subroutines will use this system routine for output to all files, +* including stdout. +* Write data via RTT. +*/ +_ssize_t _write_r(struct _reent *r, int file, const void *ptr, size_t len) { + (void) file; /* Not used, avoid warning */ + (void) r; /* Not used, avoid warning */ + SEGGER_RTT_Write(0, ptr, len); + return len; +} + +#endif +/****** End Of File *************************************************/ diff --git a/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_IAR.c b/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_IAR.c new file mode 100644 index 0000000..cc54ff4 --- /dev/null +++ b/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_IAR.c @@ -0,0 +1,119 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT_Syscalls_IAR.c +Purpose : Low-level functions for using printf() via RTT in IAR. + To use RTT for printf output, include this file in your + application and set the Library Configuration to Normal. +Revision: $Rev: 24316 $ +---------------------------------------------------------------------- +*/ +#ifdef __IAR_SYSTEMS_ICC__ + +// +// Since IAR EWARM V8 and EWRX V4, yfuns.h is considered as deprecated and LowLevelIOInterface.h +// shall be used instead. To not break any compatibility with older compiler versions, we have a +// version check in here. +// +#if ((defined __ICCARM__) && (__VER__ >= 8000000)) || ((defined __ICCRX__) && (__VER__ >= 400)) + #include +#else + #include +#endif + +#include "SEGGER_RTT.h" +#pragma module_name = "?__write" + +/********************************************************************* +* +* Function prototypes +* +********************************************************************** +*/ +size_t __write(int handle, const unsigned char * buffer, size_t size); + +/********************************************************************* +* +* Global functions +* +********************************************************************** +*/ +/********************************************************************* +* +* __write() +* +* Function description +* Low-level write function. +* Standard library subroutines will use this system routine +* for output to all files, including stdout. +* Write data via RTT. +*/ +size_t __write(int handle, const unsigned char * buffer, size_t size) { + (void) handle; /* Not used, avoid warning */ + SEGGER_RTT_Write(0, (const char*)buffer, size); + return size; +} + +/********************************************************************* +* +* __write_buffered() +* +* Function description +* Low-level write function. +* Standard library subroutines will use this system routine +* for output to all files, including stdout. +* Write data via RTT. +*/ +size_t __write_buffered(int handle, const unsigned char * buffer, size_t size) { + (void) handle; /* Not used, avoid warning */ + SEGGER_RTT_Write(0, (const char*)buffer, size); + return size; +} + +#endif +/****** End Of File *************************************************/ diff --git a/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_KEIL.c b/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_KEIL.c new file mode 100644 index 0000000..427bead --- /dev/null +++ b/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_KEIL.c @@ -0,0 +1,393 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : RTT_Syscalls_KEIL.c +Purpose : Retargeting module for KEIL MDK-CM3. + Low-level functions for using printf() via RTT +Revision: $Rev: 24316 $ +Notes : (1) https://wiki.segger.com/Keil_MDK-ARM#RTT_in_uVision +---------------------------------------------------------------------- +*/ +#if (defined __CC_ARM) || (defined __ARMCC_VERSION) + +#include +#include +#include +#include +#include + +#include "SEGGER_RTT.h" +/********************************************************************* +* +* #pragmas +* +********************************************************************** +*/ +#if __ARMCC_VERSION < 6000000 +#pragma import(__use_no_semihosting) +#endif + +#ifdef _MICROLIB + #pragma import(__use_full_stdio) +#endif + +/********************************************************************* +* +* Defines non-configurable +* +********************************************************************** +*/ + +/* Standard IO device handles - arbitrary, but any real file system handles must be + less than 0x8000. */ +#define STDIN 0x8001 // Standard Input Stream +#define STDOUT 0x8002 // Standard Output Stream +#define STDERR 0x8003 // Standard Error Stream + +/********************************************************************* +* +* Public const +* +********************************************************************** +*/ +#if __ARMCC_VERSION < 5000000 +//const char __stdin_name[] = "STDIN"; +const char __stdout_name[] = "STDOUT"; +const char __stderr_name[] = "STDERR"; +#endif + +/********************************************************************* +* +* Public code +* +********************************************************************** +*/ + +/********************************************************************* +* +* _ttywrch +* +* Function description: +* Outputs a character to the console +* +* Parameters: +* c - character to output +* +*/ +void _ttywrch(int c) { + fputc(c, stdout); // stdout + fflush(stdout); +} + +/********************************************************************* +* +* _sys_open +* +* Function description: +* Opens the device/file in order to do read/write operations +* +* Parameters: +* sName - sName of the device/file to open +* OpenMode - This parameter is currently ignored +* +* Return value: +* != 0 - Handle to the object to open, otherwise +* == 0 -"device" is not handled by this module +* +*/ +FILEHANDLE _sys_open(const char * sName, int OpenMode) { + (void)OpenMode; + // Register standard Input Output devices. + if (strcmp(sName, __stdout_name) == 0) { + return (STDOUT); + } else if (strcmp(sName, __stderr_name) == 0) { + return (STDERR); + } else + return (0); // Not implemented +} + +/********************************************************************* +* +* _sys_close +* +* Function description: +* Closes the handle to the open device/file +* +* Parameters: +* hFile - Handle to a file opened via _sys_open +* +* Return value: +* 0 - device/file closed +* +*/ +int _sys_close(FILEHANDLE hFile) { + (void)hFile; + return 0; // Not implemented +} + +/********************************************************************* +* +* _sys_write +* +* Function description: +* Writes the data to an open handle. +* Currently this function only outputs data to the console +* +* Parameters: +* hFile - Handle to a file opened via _sys_open +* pBuffer - Pointer to the data that shall be written +* NumBytes - Number of bytes to write +* Mode - The Mode that shall be used +* +* Return value: +* Number of bytes *not* written to the file/device +* +*/ +int _sys_write(FILEHANDLE hFile, const unsigned char * pBuffer, unsigned NumBytes, int Mode) { + int r = 0; + + (void)Mode; + if (hFile == STDOUT) { + SEGGER_RTT_Write(0, (const char*)pBuffer, NumBytes); + return 0; + } + return r; +} + +/********************************************************************* +* +* _sys_read +* +* Function description: +* Reads data from an open handle. +* Currently this modules does nothing. +* +* Parameters: +* hFile - Handle to a file opened via _sys_open +* pBuffer - Pointer to buffer to store the read data +* NumBytes - Number of bytes to read +* Mode - The Mode that shall be used +* +* Return value: +* Number of bytes read from the file/device +* +*/ +int _sys_read(FILEHANDLE hFile, unsigned char * pBuffer, unsigned NumBytes, int Mode) { + (void)hFile; + (void)pBuffer; + (void)NumBytes; + (void)Mode; + return (0); // Not implemented +} + +/********************************************************************* +* +* _sys_istty +* +* Function description: +* This function shall return whether the opened file +* is a console device or not. +* +* Parameters: +* hFile - Handle to a file opened via _sys_open +* +* Return value: +* 1 - Device is a console +* 0 - Device is not a console +* +*/ +int _sys_istty(FILEHANDLE hFile) { + if (hFile > 0x8000) { + return (1); + } + return (0); // Not implemented +} + +/********************************************************************* +* +* _sys_seek +* +* Function description: +* Seeks via the file to a specific position +* +* Parameters: +* hFile - Handle to a file opened via _sys_open +* Pos - +* +* Return value: +* int - +* +*/ +int _sys_seek(FILEHANDLE hFile, long Pos) { + (void)hFile; + (void)Pos; + return (0); // Not implemented +} + +/********************************************************************* +* +* _sys_ensure +* +* Function description: +* +* +* Parameters: +* hFile - Handle to a file opened via _sys_open +* +* Return value: +* int - +* +*/ +int _sys_ensure(FILEHANDLE hFile) { + (void)hFile; + return (-1); // Not implemented +} + +/********************************************************************* +* +* _sys_flen +* +* Function description: +* Returns the length of the opened file handle +* +* Parameters: +* hFile - Handle to a file opened via _sys_open +* +* Return value: +* Length of the file +* +*/ +long _sys_flen(FILEHANDLE hFile) { + (void)hFile; + return (0); // Not implemented +} + +/********************************************************************* +* +* _sys_tmpnam +* +* Function description: +* This function converts the file number fileno for a temporary +* file to a unique filename, for example, tmp0001. +* +* Parameters: +* pBuffer - Pointer to a buffer to store the name +* FileNum - file number to convert +* MaxLen - Size of the buffer +* +* Return value: +* 1 - Error +* 0 - Success +* +*/ +int _sys_tmpnam(char * pBuffer, int FileNum, unsigned MaxLen) { + (void)pBuffer; + (void)FileNum; + (void)MaxLen; + return (1); // Not implemented +} + +/********************************************************************* +* +* _sys_command_string +* +* Function description: +* This function shall execute a system command. +* +* Parameters: +* cmd - Pointer to the command string +* len - Length of the string +* +* Return value: +* == NULL - Command was not successfully executed +* == sCmd - Command was passed successfully +* +*/ +char * _sys_command_string(char * cmd, int len) { + (void)len; + return cmd; // Not implemented +} + +/********************************************************************* +* +* _sys_exit +* +* Function description: +* This function is called when the application returns from main +* +* Parameters: +* ReturnCode - Return code from the main function +* +* +*/ +void _sys_exit(int ReturnCode) { + (void)ReturnCode; + while (1); // Not implemented +} + +#if __ARMCC_VERSION >= 5000000 +/********************************************************************* +* +* stdout_putchar +* +* Function description: +* Put a character to the stdout +* +* Parameters: +* ch - Character to output +* +* +*/ +int stdout_putchar(int ch) { + (void)ch; + return ch; // Not implemented +} +#endif + +#endif +/*************************** End of file ****************************/ diff --git a/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_SES.c b/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_SES.c new file mode 100644 index 0000000..1e3e39f --- /dev/null +++ b/bsp/projects/common/segger/Syscalls/SEGGER_RTT_Syscalls_SES.c @@ -0,0 +1,251 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2021 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER SystemView * Real-time application analysis * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the SystemView and RTT protocol, and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* SystemView version: 3.32 * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT_Syscalls_SES.c +Purpose : Reimplementation of printf, puts and __getchar using RTT + in SEGGER Embedded Studio. + To use RTT for printf output, include this file in your + application. +Revision: $Rev: 24316 $ +---------------------------------------------------------------------- +*/ +#if (defined __SES_ARM) || (defined __SES_RISCV) || (defined __CROSSWORKS_ARM) + +#include "SEGGER_RTT.h" +#include +#include +#include "limits.h" +#include "__libc.h" +#include "__vfprintf.h" + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ +// +// Select string formatting implementation. +// +// RTT printf formatting +// - Configurable stack usage. (SEGGER_RTT_PRINTF_BUFFER_SIZE in SEGGER_RTT_Conf.h) +// - No maximum string length. +// - Limited conversion specifiers and flags. (See SEGGER_RTT_printf.c) +// Standard library printf formatting +// - Configurable formatting capabilities. +// - Full conversion specifier and flag support. +// - Maximum string length has to be known or (slightly) slower character-wise output. +// +// #define PRINTF_USE_SEGGER_RTT_FORMATTING 0 // Use standard library formatting +// #define PRINTF_USE_SEGGER_RTT_FORMATTING 1 // Use RTT formatting +// +#ifndef PRINTF_USE_SEGGER_RTT_FORMATTING + #define PRINTF_USE_SEGGER_RTT_FORMATTING 0 +#endif +// +// If using standard library formatting, +// select maximum output string buffer size or character-wise output. +// +// #define PRINTF_BUFFER_SIZE 0 // Use character-wise output +// #define PRINTF_BUFFER_SIZE 128 // Default maximum string length +// +#ifndef PRINTF_BUFFER_SIZE + #define PRINTF_BUFFER_SIZE 128 +#endif + +#if PRINTF_USE_SEGGER_RTT_FORMATTING // Use SEGGER RTT formatting implementation +/********************************************************************* +* +* Function prototypes +* +********************************************************************** +*/ +int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList); + +/********************************************************************* +* +* Global functions, printf +* +********************************************************************** +*/ +/********************************************************************* +* +* printf() +* +* Function description +* print a formatted string using RTT and SEGGER RTT formatting. +*/ +int printf(const char *fmt,...) { + int n; + va_list args; + + va_start (args, fmt); + n = SEGGER_RTT_vprintf(0, fmt, &args); + va_end(args); + return n; +} + +#elif PRINTF_BUFFER_SIZE == 0 // Use standard library formatting with character-wise output + +/********************************************************************* +* +* Static functions +* +********************************************************************** +*/ +static int _putchar(int x, __printf_tag_ptr ctx) { + (void)ctx; + SEGGER_RTT_Write(0, (char *)&x, 1); + return x; +} + +/********************************************************************* +* +* Global functions, printf +* +********************************************************************** +*/ +/********************************************************************* +* +* printf() +* +* Function description +* print a formatted string character-wise, using RTT and standard +* library formatting. +*/ +int printf(const char *fmt, ...) { + int n; + va_list args; + __printf_t iod; + + va_start(args, fmt); + iod.string = 0; + iod.maxchars = INT_MAX; + iod.output_fn = _putchar; + SEGGER_RTT_LOCK(); + n = __vfprintf(&iod, fmt, args); + SEGGER_RTT_UNLOCK(); + va_end(args); + return n; +} + +#else // Use standard library formatting with static buffer + +/********************************************************************* +* +* Global functions, printf +* +********************************************************************** +*/ +/********************************************************************* +* +* printf() +* +* Function description +* print a formatted string using RTT and standard library formatting. +*/ +int printf(const char *fmt,...) { + int n; + char aBuffer[PRINTF_BUFFER_SIZE]; + va_list args; + + va_start (args, fmt); + n = vsnprintf(aBuffer, sizeof(aBuffer), fmt, args); + if (n > (int)sizeof(aBuffer)) { + SEGGER_RTT_Write(0, aBuffer, sizeof(aBuffer)); + } else if (n > 0) { + SEGGER_RTT_Write(0, aBuffer, n); + } + va_end(args); + return n; +} +#endif + +/********************************************************************* +* +* Global functions +* +********************************************************************** +*/ +/********************************************************************* +* +* puts() +* +* Function description +* print a string using RTT. +*/ +int puts(const char *s) { + return SEGGER_RTT_WriteString(0, s); +} + +/********************************************************************* +* +* __putchar() +* +* Function description +* Write one character via RTT. +*/ +int __putchar(int x, __printf_tag_ptr ctx) { + (void)ctx; + SEGGER_RTT_Write(0, (char *)&x, 1); + return x; +} + +/********************************************************************* +* +* __getchar() +* +* Function description +* Wait for and get a character via RTT. +*/ +int __getchar() { + return SEGGER_RTT_WaitKey(); +} + +#endif +/****** End Of File *************************************************/ diff --git a/bsp/projects/common/segger/utility_segger.cmake b/bsp/projects/common/segger/utility_segger.cmake new file mode 100644 index 0000000..9257b37 --- /dev/null +++ b/bsp/projects/common/segger/utility_segger.cmake @@ -0,0 +1,23 @@ +include_guard() +message("segger component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE +"${CMAKE_CURRENT_LIST_DIR}/SEGGER.h" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_RTT.c" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_RTT.h" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_RTT_ASM_ARMv7M.S" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_RTT_printf.c" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_SYSVIEW.c" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_SYSVIEW.h" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_SYSVIEW_ConfDefaults.h" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_SYSVIEW_FreeRTOS.c" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_SYSVIEW_FreeRTOS.h" +"${CMAKE_CURRENT_LIST_DIR}/SEGGER_SYSVIEW_Int.h" +"${CMAKE_CURRENT_LIST_DIR}/Syscalls/SEGGER_RTT_Syscalls_GCC.c" +"${CMAKE_CURRENT_LIST_DIR}/Config/Cortex-M/SEGGER_SYSVIEW_Config_FreeRTOS.c" +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/. + ${CMAKE_CURRENT_LIST_DIR}/Config/. +) diff --git a/bsp/projects/microej/.project b/bsp/projects/microej/.project new file mode 100644 index 0000000..53d4a91 --- /dev/null +++ b/bsp/projects/microej/.project @@ -0,0 +1,11 @@ + + + microej + + + + + + + + diff --git a/bsp/projects/microej/README.rst b/bsp/projects/microej/README.rst new file mode 100644 index 0000000..5dfad8c --- /dev/null +++ b/bsp/projects/microej/README.rst @@ -0,0 +1,99 @@ +.. + Copyright 2022-2023 MicroEJ Corp. All rights reserved. + Use of this source code is governed by a BSD-style license that can be found with this software. + +.. |BOARD_NAME| replace:: RW612-BGA EVK +.. |VEEPORT| replace:: VEE Port +.. |RTOS| replace:: FreeRTOS +.. |BSP_FULL_NAME| replace:: MCUXpresso Software Development Kit +.. |BSP_SHORT_NAME| replace:: SDK_2_12_1_RDRW610 + +.. _README: ./../../../README.rst + +================ +|BOARD_NAME| BSP +================ + +This project contains the BSP sources of the |VEEPORT| for the +|BOARD_NAME|. The BSP project is based on |BSP_FULL_NAME| (|BSP_SHORT_NAME|). + +This document does not describe how to setup the |VEEPORT|. Please +refer to the `README`_ for that. + +Build & Run Scripts +--------------------- + +In the directory ``Project/microej/scripts/`` are scripts that can be +used to build and flash the BSP. The ``.bat`` and ``.sh`` scripts are +meant to run in a Windows and Linux environment respectively. + +- The ``build*`` scripts are used to compile and link the BSP with a + MicroEJ Application to produce a MicroEJ Firmware + (``application.out``) that can be flashed on a device. + + The ``build*`` scripts work out of the box, assuming the toolchain is + installed in the default path. + +- The ``run*`` scripts is not available yet. + +The following environment variables are customizable: + +**IAR toolchain** + +- ``IAREW_INSTALLATION_DIR``: The path to IAR installation directory (already set to the default IAR Workbench default installation directory). +- ``IAREW_PROJECT_CONFIGURATION``: The project configuration (``Debug`` or ``Release``). +- ``IAREW_PROJECT_DIR``: The directory that contains the ``application.eww`` IAR project file (set to ``%~dp0``: the directory that contains the executed ``.bat``). +- ``IAREW_PROJECT_NAME``: The Eclipse CDT project name (``application`` by default). +- ``IAREW_OUT_FILENAME``: The output file name. +- ``IAREW_PROJECT_DEVICE_MACRO``: Device macro file depending on the board. +- ``IAREW_PROJECT_FLASH_LOADER``: Device flash loader file depending on the board. + +The environment variables can be defined globally by the user or in +the ``set_local_env*`` scripts. When the ``.bat`` (``.sh``) scripts +are executed, the ``set_local_env.bat`` (``set_local_env.sh``) script +is executed if it exists. Create and configure these files to +customize the environment locally. Template files are provided as +example, see ``set_local_env.bat.tpl`` and ``set_local_env.sh.tpl``. + +Customize BSP +------------- + +Flash the Board +--------------- + +To flash the board with IAR, go to ``Project > Download > Download active application``. + +Debugging with |BOARD_NAME| +--------------------------- + +- Open the file ``-bsp/projects/microej/EWARM/set_project_env.bat``. +- Set the target configuration to ``Debug``. + +.. code-block:: + + SET IAREW_PROJECT_CONFIGURATION=Debug + +- Open the IAR project in IAR Workbench (open the file ``-bsp/projects/microej/iar/application.eww`` from IAR Workbench or by double-clicking on it from the MicroEJ SDK). +- Ensure that the ``debug`` target is selected in the workspace tab +- Build and link the firmware: Right-click on the ``application`` project > ``Make`` or Press 'F7' +- Connect the |BOARD_NAME| to your computer +- Start the debug session by clicking on ``Project`` > ``Download and Debug`` + +Running EmbUnit & CoreMark benchs +================================= + +To execute the EmbUnit and CoreMark benchs: + +- Open the IAR project in IAR Workbench (open the file ``-bsp/projects/microej/iar/application.eww`` from IAR Workbench or by double-clicking on it from the MicroEJ SDK). +- Select the ``UnitTest`` target is selected in the workspace tab. +- Build and link the firmware: Right-click on the ``application`` project > ``Make`` or Press 'F7'. +- Connect the |BOARD_NAME| to your computer. +- Start the debug session by clicking on ``Project`` > ``Download and Debug``. + +Troubleshooting +=============== + +Can not connect to the board with J-LINK +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- To unlock the board, remove jumper 3-4 of HD12, you can be able to connect J-Link and flash a correct image and put the jumper back to boot up. diff --git a/bsp/projects/microej/ai/inc/TfLiteSupportImpl.h b/bsp/projects/microej/ai/inc/TfLiteSupportImpl.h new file mode 100644 index 0000000..1debcbd --- /dev/null +++ b/bsp/projects/microej/ai/inc/TfLiteSupportImpl.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TFLITE_SUPPORT_IMPL +#define TFLITE_SUPPORT_IMPL + +#include "tensorflow/lite/micro/kernels/micro_ops.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/schema/schema_generated.h" + +#include "fsl_debug_console.h" +class TfLiteSupportImpl +{ + public: + TfLiteSupportImpl(const void *modelData, size_t arena_size); + + ~TfLiteSupportImpl(); + + template + T* GetInputData(int idx) { return interpreter->typed_input_tensor(idx); } + template + T* GetOutputData(int idx) { return interpreter->typed_output_tensor(idx); } + TfLiteTensor* GetInputTensor(int idx) { return interpreter->input_tensor(idx); } + TfLiteTensor* GetOutputTensor(int idx) { return interpreter->output_tensor(idx); } + + int RunInference(); + + private: + const uint8_t *model_data; + tflite::MicroOpResolver* micro_op_resolver; + const tflite::Model *model; + tflite::MicroInterpreter *interpreter; + uint8_t *tensor_arena; +}; + +#endif diff --git a/bsp/projects/microej/ai/inc/TfLiteSupportInterface.h b/bsp/projects/microej/ai/inc/TfLiteSupportInterface.h new file mode 100644 index 0000000..ca33610 --- /dev/null +++ b/bsp/projects/microej/ai/inc/TfLiteSupportInterface.h @@ -0,0 +1,45 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TFLITESUPPORTINTERFACE_H +#define TFLITESUPPORTINTERFACE_H + +#include +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_MODEL_NUMBER 4 +typedef int NXPVEE_handle_t; + +NXPVEE_handle_t NXPEE_AI_TfLiteMicroSetUp(void* model_data, int arena_size); +int NXPVEE_AI_TfLiteMicroTearDown(int handle); + +int NXPVEE_AI_TfLiteMicroGetInputTensorSize(int handle, int idx); +int NXPVEE_AI_TfLiteMicroGetInputTensorDims(int handle, int idx, int* sizes); +int NXPVEE_AI_TfLiteMicroGetInputTensorType(int handle, int idx); + +int NXPVEE_AI_TfLiteMicroGetOutputTensorSize(int handle, int idx); +int NXPVEE_AI_TfLiteMicroGetOutputTensorDims(int handle, int idx, int* sizes); +int NXPVEE_AI_TfLiteMicroGetOutputTensorType(int handle, int idx); + +int NXPVEE_AI_TfLiteMicroSetInputTensorInt8(int handle, int idx, const int8_t* src, int len); +int NXPVEE_AI_TfLiteMicroSetInputTensorUInt8(int handle, int idx, const uint8_t* src, int len); +int NXPVEE_AI_TfLiteMicroSetInputTensorFloat32(int handle, int idx, const float* src, int len); + +int NXPVEE_AI_TfLiteMicroGetOutputTensorInt8(int handle, int idx, int8_t* dst, int len); +int NXPVEE_AI_TfLiteMicroGetOutputTensorUInt8(int handle, int idx, uint8_t* dst, int len); +int NXPVEE_AI_TfLiteMicroGetOutputTensorFloat32(int handle, int idx, float* dst, int len); + +int NXPVEE_AI_TfLiteMicroRunInference(int handle); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/bsp/projects/microej/ai/nxpvee_ai.cmake b/bsp/projects/microej/ai/nxpvee_ai.cmake new file mode 100644 index 0000000..03e6e54 --- /dev/null +++ b/bsp/projects/microej/ai/nxpvee_ai.cmake @@ -0,0 +1,15 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: BSD-3-Clause + +include_guard() +message("nxpvee/ai component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/LLAI_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/TfLiteSupportImpl.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/TfLiteSupportInterface.cpp +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/inc +) diff --git a/bsp/projects/microej/ai/src/LLAI_impl.c b/bsp/projects/microej/ai/src/LLAI_impl.c new file mode 100644 index 0000000..fa3eef5 --- /dev/null +++ b/bsp/projects/microej/ai/src/LLAI_impl.c @@ -0,0 +1,111 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "TfLiteSupportInterface.h" +#include "LLMJVM.h" +#include + +typedef struct +{ + void* data; + uint32_t size; +} java_resource; + +uint32_t LLAI_IMPL_function(void) +{ + return 0; +} + +int LLAI_IMPL_TfLiteMicroSetUp(char* model_path, int len, int arena_size) +{ + java_resource resource; + int32_t ret = LLMJVM_getJavaResource(model_path, len, &resource); + if (ret == 0) + { + return NXPEE_AI_TfLiteMicroSetUp(resource.data, arena_size); + } + else + { + return -1; + } +} + +int LLAI_IMPL_TfLiteMicroTearDown(int handle) +{ + return NXPVEE_AI_TfLiteMicroTearDown(handle); +} + +/* Get input tensor data */ +int LLAI_IMPL_GetInputTensorSize(int handle, int idx) +{ + return NXPVEE_AI_TfLiteMicroGetInputTensorSize(handle, idx); +} + +int LLAI_IMPL_GetInputTensorDims(int handle, int idx, int* sizes) +{ + return NXPVEE_AI_TfLiteMicroGetInputTensorDims(handle, idx, sizes); +} + +int LLAI_IMPL_GetInputTensorType(int handle, int idx) +{ + return NXPVEE_AI_TfLiteMicroGetInputTensorType(handle, idx); +} + +/* Get output tensor data */ +int LLAI_IMPL_GetOutputTensorSize(int handle, int idx) +{ + return NXPVEE_AI_TfLiteMicroGetOutputTensorSize(handle, idx); +} + +int LLAI_IMPL_GetOutputTensorDims(int handle, int idx, int* sizes) +{ + return NXPVEE_AI_TfLiteMicroGetOutputTensorDims(handle, idx, sizes); +} + +int LLAI_IMPL_GetOutputTensorType(int handle, int idx) +{ + return NXPVEE_AI_TfLiteMicroGetOutputTensorType(handle, idx); +} + +/* Set input data */ +int LLAI_IMPL_SetInputDataInt8(int handle, int idx, int8_t* src, int len) +{ + return NXPVEE_AI_TfLiteMicroSetInputTensorInt8(handle, idx, src, len); +} + +int LLAI_IMPL_SetInputDataUInt8(int handle, int idx, uint8_t* src, int len) +{ + return NXPVEE_AI_TfLiteMicroSetInputTensorUInt8(handle, idx, src, len); +} + +int LLAI_IMPL_SetInputDataFloat32(int handle, int idx, float* src, int len) +{ + return NXPVEE_AI_TfLiteMicroSetInputTensorFloat32(handle, idx, src, len); +} + +/* Get output data */ +int LLAI_IMPL_GetOutputDataInt8(int handle, int idx, int8_t* dst, int len) +{ + return NXPVEE_AI_TfLiteMicroGetOutputTensorInt8(handle, idx, dst, len); +} + +int LLAI_IMPL_GetOutputDataUInt8(int handle, int idx, uint8_t* dst, int len) +{ + return NXPVEE_AI_TfLiteMicroGetOutputTensorUInt8(handle, idx, dst, len); +} + +int LLAI_IMPL_GetOutputDataFloat32(int handle, int idx, float* dst, int len) +{ + return NXPVEE_AI_TfLiteMicroGetOutputTensorFloat32(handle, idx, dst, len); +} + +/* Run inference */ +int LLAI_IMPL_RunInference(int handle) +{ + return NXPVEE_AI_TfLiteMicroRunInference(handle); +} diff --git a/bsp/projects/microej/ai/src/TfLiteSupportImpl.cpp b/bsp/projects/microej/ai/src/TfLiteSupportImpl.cpp new file mode 100644 index 0000000..68fccc0 --- /dev/null +++ b/bsp/projects/microej/ai/src/TfLiteSupportImpl.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "TfLiteSupportImpl.h" +#include "fsl_debug_console.h" +#include "tensorflow/lite/micro/micro_op_resolver.h" + +TfLiteSupportImpl::TfLiteSupportImpl(const void *modelData, size_t arena_size) +{ + model = tflite::GetModel(modelData); + if(model == nullptr) + { + PRINTF("ERROR: failed to get model\r\n"); + } + assert (model != nullptr); + + // Allocate arena tensor memory + tensor_arena = new uint8_t[arena_size]; + if(tensor_arena == nullptr) + { + PRINTF("ERROR: failed to allocate tensor arena\r\n"); + } + assert (tensor_arena != nullptr); + + extern tflite::MicroOpResolver* AI_GetOpsResolver(); + micro_op_resolver = AI_GetOpsResolver(); + if(micro_op_resolver == nullptr) + { + PRINTF("ERROR: failed to get micro operations resolver\r\n"); + } + assert (micro_op_resolver != nullptr); + + // Build an interpreter to run the model with + interpreter = new tflite::MicroInterpreter(model, *micro_op_resolver, + tensor_arena, arena_size); + if(interpreter == nullptr) + { + PRINTF("ERROR: failed to initialize interpreter\r\n"); + } + assert (interpreter != nullptr); + + // Allocate memory from the tensor_arena for the model's tensor + if(interpreter->AllocateTensors() != kTfLiteOk) + { + PRINTF("Allocate tensor failed\r\n"); + assert (1 == 0); + } +} + +TfLiteSupportImpl::~TfLiteSupportImpl() +{ + delete [] tensor_arena; + delete(interpreter); +} + +int TfLiteSupportImpl::RunInference() +{ + int ret = 0; + + TfLiteStatus invoke_status = interpreter->Invoke(); + if (invoke_status != kTfLiteOk) + { + PRINTF("Interpreter invocation failed\r\n"); + ret = kTfLiteError; + } + return ret; +} diff --git a/bsp/projects/microej/ai/src/TfLiteSupportInterface.cpp b/bsp/projects/microej/ai/src/TfLiteSupportInterface.cpp new file mode 100644 index 0000000..23e12e6 --- /dev/null +++ b/bsp/projects/microej/ai/src/TfLiteSupportInterface.cpp @@ -0,0 +1,228 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "TfLiteSupportInterface.h" +#include "TfLiteSupportImpl.h" +#include + +#include "fsl_debug_console.h" + +static TfLiteSupportImpl *models_g[MAX_MODEL_NUMBER] = {nullptr, nullptr, nullptr, nullptr}; + + +extern "C" +NXPVEE_handle_t NXPEE_AI_TfLiteMicroSetUp(void* model_data, int arena_size) +{ + int handle = 0; + for (handle = 0; handle < MAX_MODEL_NUMBER; handle++) + { + if (nullptr == models_g[handle]) + { + TfLiteSupportImpl *impl = new TfLiteSupportImpl(model_data, arena_size); + assert (impl != nullptr); + + models_g[handle] = impl; + break; + } + } + assert (handle != MAX_MODEL_NUMBER); + + return handle; +} + +int NXPVEE_AI_TfLiteMicroTearDown(int handle) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl!=nullptr); + + delete impl; + models_g[handle] = nullptr; + + return 0; +} + +// Get input tensor data +extern "C" +int NXPVEE_AI_TfLiteMicroGetInputTensorSize(int handle, int idx) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + TfLiteTensor* t = impl->GetInputTensor(idx); + assert (t != nullptr); + + return t->dims->size; +} + +extern "C" +int NXPVEE_AI_TfLiteMicroGetInputTensorDims(int handle, int idx, int* sizes) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + TfLiteTensor* t = impl->GetInputTensor(idx); + assert (t != nullptr); + + TfLiteIntArray* idims = t->dims; + for (int i = 0; i < idims->size; i++) + { + sizes[i] = idims->data[i]; + } + + return 0; +} + +extern "C" +int NXPVEE_AI_TfLiteMicroGetInputTensorType(int handle, int idx) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + TfLiteTensor* t = impl->GetInputTensor(idx); + assert (t != nullptr); + + return t->type; +} + +// Get output tensor data +extern "C" +int NXPVEE_AI_TfLiteMicroGetOutputTensorSize(int handle, int idx) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + TfLiteTensor* t = impl->GetOutputTensor(idx); + assert (t != nullptr); + + return t->dims->size; +} + +extern "C" +int NXPVEE_AI_TfLiteMicroGetOutputTensorDims(int handle, int idx, int* sizes) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + TfLiteTensor* t = impl->GetOutputTensor(idx); + assert (t != nullptr); + + TfLiteIntArray* idims = t->dims; + for (int i = 0; i < idims->size; i++) + { + sizes[i] = idims->data[i]; + } + + return 0; +} + +extern "C" +int NXPVEE_AI_TfLiteMicroGetOutputTensorType(int handle, int idx) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + TfLiteTensor* t = impl->GetOutputTensor(idx); + assert (t != nullptr); + + return t->type; +} + + +// Set input data +extern "C" +int NXPVEE_AI_TfLiteMicroSetInputTensorInt8(int handle, int idx, const int8_t* src, int len) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + int8_t* dst = impl->GetInputData(idx); + assert (dst != nullptr); + assert (src != nullptr); + + memcpy(dst, src, len*sizeof(int8_t)); + return 0; +} + +extern "C" +int NXPVEE_AI_TfLiteMicroSetInputTensorUInt8(int handle, int idx, const uint8_t* src, int len) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + uint8_t* dst = impl->GetInputData(idx); + assert (dst != nullptr); + assert (src != nullptr); + + memcpy(dst, src, len*sizeof(uint8_t)); + return 0; +} + +extern "C" +int NXPVEE_AI_TfLiteMicroSetInputTensorFloat32(int handle, int idx, const float* src, int len) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + float* dst = impl->GetInputData(idx); + assert (dst != nullptr); + assert (src != nullptr); + + memcpy(dst, src, len*sizeof(float)); + return 0; +} + +// Get output data +extern "C" +int NXPVEE_AI_TfLiteMicroGetOutputTensorInt8(int handle, int idx, int8_t* dst, int len) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + int8_t* src = impl->GetOutputData(idx); + assert (dst != nullptr); + assert (src != nullptr); + + memcpy(dst, src, len*sizeof(int8_t)); + return 0; +} + +extern "C" +int NXPVEE_AI_TfLiteMicroGetOutputTensorUInt8(int handle, int idx, uint8_t* dst, int len) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + uint8_t* src = impl->GetOutputData(idx); + assert (dst != nullptr); + assert (src != nullptr); + + memcpy(dst, src, len*sizeof(uint8_t)); + return 0; +} + +extern "C" +int NXPVEE_AI_TfLiteMicroGetOutputTensorFloat32(int handle, int idx, float* dst, int len) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + float* src = impl->GetOutputData(idx); + assert (dst != nullptr); + assert (src != nullptr); + + memcpy(dst, src, len*sizeof(float)); + return 0; +} + +// Run inference +extern "C" +int NXPVEE_AI_TfLiteMicroRunInference(int handle) +{ + TfLiteSupportImpl *impl = models_g[handle]; + assert (impl != nullptr); + + return impl->RunInference(); +} diff --git a/bsp/projects/microej/core/inc/LLMJVM_FreeRTOS_configuration.h b/bsp/projects/microej/core/inc/LLMJVM_FreeRTOS_configuration.h new file mode 100644 index 0000000..3669bae --- /dev/null +++ b/bsp/projects/microej/core/inc/LLMJVM_FreeRTOS_configuration.h @@ -0,0 +1,21 @@ +/* + * C + * + * Copyright 2021 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + */ + +#ifndef _LLMJVM_FREERTOS_CONFIGURATION_H +#define _LLMJVM_FREERTOS_CONFIGURATION_H + +/* Defines used to include FreeRTOS API header files. Update it if header file location is different. */ + +#define FREERTOS_HEADER "FreeRTOS.h" +#define FREERTOS_TIMERS_HEADER "timers.h" +#define FREERTOS_SEMPHR_HEADER "semphr.h" +#define FREERTOS_TASK_HEADER "task.h" +#define YIELD_FROM_ISR(x) portYIELD_FROM_ISR(x) +#define IS_INSIDE_INTERRUPT xPortIsInsideInterrupt + +#endif /* _LLMJVM_FREERTOS_CONFIGURATION_H */ diff --git a/bsp/projects/microej/core/inc/cpuload.h b/bsp/projects/microej/core/inc/cpuload.h new file mode 100644 index 0000000..0068a3f --- /dev/null +++ b/bsp/projects/microej/core/inc/cpuload.h @@ -0,0 +1,55 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ +#ifndef _CPULOAD_INTERN +#define _CPULOAD_INTERN + +/* Includes ------------------------------------------------------------------*/ + +#include +#include "cpuload_conf.h" + +/* Defines -------------------------------------------------------------------*/ + +#ifndef CPULOAD_SCHEDULE_TIME +#define CPULOAD_SCHEDULE_TIME 500 // ms +#endif + +#define CPULOAD_OK 0 +#define CPULOAD_NOT_ENABLED -1 +#define CPULOAD_INVALID_COUNTER -2 +#define CPULOAD_START_TASK_ERROR -3 + +/* API -----------------------------------------------------------------------*/ + +/* + * Initialize the framework + * Must be called in very first OS stack. No more task must run + * at same time. + */ +int32_t cpuload_init(void); + +/* + * Must be called by the OS idle function + */ +void cpuload_idle(void); + +/* + * Return the last CPU load measure + */ +uint32_t cpuload_get(void); + +/* Default Java API ----------------------------------------------------------*/ + +#ifndef javaCPULoadInit +#define javaCPULoadInit Java_com_is2t_debug_CPULoad_init +#endif + +#ifndef javaCPULoadGet +#define javaCPULoadGet Java_com_is2t_debug_CPULoad_get +#endif + +#endif // _CPULOAD_INTERN diff --git a/bsp/projects/microej/core/inc/cpuload_conf.h b/bsp/projects/microej/core/inc/cpuload_conf.h new file mode 100644 index 0000000..09f3db4 --- /dev/null +++ b/bsp/projects/microej/core/inc/cpuload_conf.h @@ -0,0 +1,17 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ +#ifndef _CPULOAD_CONF +#define _CPULOAD_CONF + +/* Defines -------------------------------------------------------------------*/ + +/* + * Comment / uncomment it to enable / disable the CPU load measure + */ +#define CPULOAD_ENABLED + +#endif diff --git a/bsp/projects/microej/core/inc/cpuload_impl.h b/bsp/projects/microej/core/inc/cpuload_impl.h new file mode 100644 index 0000000..3e2c251 --- /dev/null +++ b/bsp/projects/microej/core/inc/cpuload_impl.h @@ -0,0 +1,55 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * Implement the *_impl* functions according the CPU/OS/Compiler + */ + +#ifndef _CPULOAD_IMPL +#define _CPULOAD_IMPL + +/* Includes ------------------------------------------------------------------*/ + +#include "cpuload.h" + +/* API -----------------------------------------------------------------------*/ + +#ifdef CPULOAD_ENABLED + +/* + * CPULoad measure task. Must be called by a dedicated OS task. + */ +void cpuload_task(void); + +/* + * Create and start a OS idle task. + * May be useless if there is already an idle routine provided by the OS. + * Return 0 when no error + */ +int32_t cpuload_impl_start_idle_task(void); + +/** + * Wait until the next OS tick. + * This function ensures that we are closely synchronized with OS tick. + * This prevents the next sleep of 1 tick takes much less time than 1 tick. + */ +void cpuload_impl_sync_os_tick(void); + +/* + * Create and start a cpuload dedicated OS task. + * Return 0 when no error + */ +int32_t cpuload_impl_start_task(void); + +/* + * Sleep the cpuload task . + */ +void cpuload_impl_sleep(uint32_t ms); + +#endif // CPULOAD_ENABLED + +#endif // _CPULOAD_IMPL diff --git a/bsp/projects/microej/core/inc/fault_handlers.h b/bsp/projects/microej/core/inc/fault_handlers.h new file mode 100644 index 0000000..5b67cef --- /dev/null +++ b/bsp/projects/microej/core/inc/fault_handlers.h @@ -0,0 +1,16 @@ +/* + * C + * + * Copyright 2014-2020 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + */ +#ifndef FAULT_HANDLERS_H +#define FAULT_HANDLERS_H + +void HardFault_Handler(void); +void MemFault_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); + +#endif // FAULT_HANDLERS_H diff --git a/bsp/projects/microej/core/inc/microej_main.h b/bsp/projects/microej/core/inc/microej_main.h new file mode 100644 index 0000000..dae2bf9 --- /dev/null +++ b/bsp/projects/microej/core/inc/microej_main.h @@ -0,0 +1,36 @@ +/* + * C + * + * Copyright 2020 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + * + */ + +/** + * @file + * @brief MicroEJ startup. + * @author MicroEJ Developer Team + * @version 2.0.0 + * @date 15 September 2020 + */ + +#ifndef MICROEJ_MAIN_H_ +#define MICROEJ_MAIN_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Creates and starts a MicroEJ instance. This function returns when the MicroEJ execution ends. + * @param argc arguments count + * @param argv arguments vector + */ +void microej_main(int argc, char **argv); + +#ifdef __cplusplus + } +#endif + +#endif /* MICROEJ_MAIN_H_ */ diff --git a/bsp/projects/microej/core/inc/microej_time.h b/bsp/projects/microej/core/inc/microej_time.h new file mode 100644 index 0000000..b0da197 --- /dev/null +++ b/bsp/projects/microej/core/inc/microej_time.h @@ -0,0 +1,71 @@ +/* + * C + * + * Copyright 2018-2021 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + */ + +/** + * @brief This is the definition of the MicroEJ time API. + * + * To implement this API the use of a hardware timer is recommended. The validation is done with the Core Engine Test Suite: https://github.com/MicroEJ/PlatformQualificationTools/tree/master/tests/core + * + * There are 2 types of time in MicroEJ: + * - The platform time: an arbitrary time that is only relevant to measure elapsed time + * - The application time: the time elapsed since midnight, January 1, 1970 UTC, this time should be set by the MicroEJ application + * + * An implementation example is available on Espressif WROVER: https://github.com/MicroEJ/Platform-Espressif-ESP-WROVER-KIT-V4.1/blob/master/ESP32-WROVER-Xtensa-FreeRTOS-bsp/Projects/microej/core/src/microej_time.c + * + */ + +#ifndef MICROEJ_TIME_H +#define MICROEJ_TIME_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Initialisation of the timebase used by MicroEJ. Initialize in this function everything that is needed to implement the API. + * + */ +void microej_time_init(void); + +/** + * @brief Gets the current platform or application time. + * + * @param is_platform_time set to 1 to get the platform time or set to 0 to get the time elapsed since midnight, January 1, 1970 UTC. + * @return int64_t the time in milliseconds. + */ +int64_t microej_time_get_current_time(uint8_t is_platform_time); + +/** + * @brief Gets an arbitrary time. + * + * @return int64_t the time in nanoseconds. The time should have a nanosecond precision but not necessarily nanosecond resolution. + */ +int64_t microej_time_get_time_nanos(void); + +/** + * @brief Sets the application time. + * + * @param time value in milliseconds of the time elapsed since midnight, January 1, 1970 UTC. + */ +void microej_time_set_application_time(int64_t time); + +/** + * @brief Converts a time in milliseconds to a number of system ticks. + * + * @param time the time to convert in milliseconds, + * @return int64_t the number of ticks. + */ +int64_t microej_time_time_to_tick(int64_t time); + +#ifdef __cplusplus + } +#endif + +#endif /* _MICROEJ_TIME_H */ diff --git a/bsp/projects/microej/core/inc/microej_time_freertos_configuration.h b/bsp/projects/microej/core/inc/microej_time_freertos_configuration.h new file mode 100644 index 0000000..ca02220 --- /dev/null +++ b/bsp/projects/microej/core/inc/microej_time_freertos_configuration.h @@ -0,0 +1,21 @@ +/* + * C + * + * Copyright 2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** +* @file +* @brief MicroEJ Time APIs implementation for FreeRTOS. +* @author MicroEJ Developer Team +* @version 0.1.0 +*/ + +#ifndef MICROEJ_TIME_FREERTOS_CONFIGURATION_H +#define MICROEJ_TIME_FREERTOS_CONFIGURATION_H + +#define FREERTOS_HEADER "FreeRTOS.h" +#define FREERTOS_TASK_HEADER "task.h" + +#endif /** MICROEJ_TIME_FREERTOS_CONFIGURATION_H **/ diff --git a/bsp/projects/microej/core/inc/misra_2004_conf.h b/bsp/projects/microej/core/inc/misra_2004_conf.h new file mode 100644 index 0000000..a28f647 --- /dev/null +++ b/bsp/projects/microej/core/inc/misra_2004_conf.h @@ -0,0 +1,84 @@ +/* + * C + * + * Copyright 2021 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + */ + +#ifndef _MISRA_2004_CONF_H +#define _MISRA_2004_CONF_H + +#ifdef __ICCARM__ + +#define MISRA_2004_DISABLE_ALL _Pragma ("diag_suppress= \ + Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,Pm011,\ + Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\ + Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\ + Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\ + Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\ + Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\ + Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\ + Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\ + Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\ + Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\ + Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\ + Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\ + Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\ + Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\ + Pm155") + +#define MISRA_2004_ENABLE_ALL _Pragma ("diag_default= \ + Pm001,Pm002,Pm003,Pm004,Pm005,Pm006,Pm007,Pm008,Pm009,Pm010,\ + Pm012,Pm013,Pm014,Pm015,Pm016,Pm017,Pm018,Pm019,Pm020,Pm021,Pm022,\ + Pm023,Pm024,Pm025,Pm026,Pm027,Pm028,Pm029,Pm030,Pm031,Pm032,Pm033,\ + Pm034,Pm035,Pm036,Pm037,Pm038,Pm039,Pm040,Pm041,Pm042,Pm043,Pm044,\ + Pm045,Pm046,Pm047,Pm048,Pm049,Pm050,Pm051,Pm052,Pm053,Pm054,Pm055,\ + Pm056,Pm057,Pm058,Pm059,Pm060,Pm061,Pm062,Pm063,Pm064,Pm065,Pm066,\ + Pm067,Pm068,Pm069,Pm070,Pm071,Pm072,Pm073,Pm074,Pm075,Pm076,Pm077,\ + Pm078,Pm079,Pm080,Pm081,Pm082,Pm083,Pm084,Pm085,Pm086,Pm087,Pm088,\ + Pm089,Pm090,Pm091,Pm092,Pm093,Pm094,Pm095,Pm096,Pm097,Pm098,Pm099,\ + Pm100,Pm101,Pm102,Pm103,Pm104,Pm105,Pm106,Pm107,Pm108,Pm109,Pm110,\ + Pm111,Pm112,Pm113,Pm114,Pm115,Pm116,Pm117,Pm118,Pm119,Pm120,Pm121,\ + Pm122,Pm123,Pm124,Pm125,Pm126,Pm127,Pm128,Pm129,Pm130,Pm131,Pm132,\ + Pm133,Pm134,Pm135,Pm136,Pm137,Pm138,Pm139,Pm140,Pm141,Pm142,Pm143,\ + Pm144,Pm145,Pm146,Pm147,Pm148,Pm149,Pm150,Pm151,Pm152,Pm153,Pm154,\ + Pm155") + +MISRA_2004_ENABLE_ALL + +/* Project level MISRA C settings + * + * Suppressed messages: + * + * IAR diagnostic message Pm011 + * MISRA C 2004 rule 6.3 + * Typedefs that indicate size and signedness should be used in place of the basic numerical types. + * This advisory MISRA rule is temporarily suppressed as the boolean type definition (from ) used to interface with LLMJVM does not meet this criterion. + * It might be possible to define a custom-made boolean type (such as typedef uint32_t bool) which would solve this issue. + * + * IAR diagnostic message Pm140 + * MISRA rule 11.3 + * pvTimerGetTimerID returns a void* which has to be cast to an integer so as to be compared against the timer id, therefore MISRA rule 11.3 is broken. + * + */ + +#define MISRA_2004_DISABLE_RULE_6_3 _Pragma ("diag_suppress=Pm011") +#define MISRA_2004_DISABLE_RULE_10_6 _Pragma ("diag_suppress=Pm127") +#define MISRA_2004_DISABLE_RULE_11_3 _Pragma ("diag_suppress=Pm140") +#define MISRA_2004_DISABLE_RULE_14_3 _Pragma ("diag_suppress=Pm050") +#define MISRA_2004_DISABLE_RULE_16_4 _Pragma ("diag_suppress=Pm069") + +#else /* Disable MISRA rules check by IAR */ + +#define MISRA_2004_DISABLE_ALL +#define MISRA_2004_ENABLE_ALL +#define MISRA_2004_DISABLE_RULE_6_3 +#define MISRA_2004_DISABLE_RULE_10_6 +#define MISRA_2004_DISABLE_RULE_11_3 +#define MISRA_2004_DISABLE_RULE_14_3 +#define MISRA_2004_DISABLE_RULE_16_4 + +#endif /* __ICCARM__ */ + +#endif /* _MISRA_2004_CONF_H */ diff --git a/bsp/projects/microej/core/microej_core.cmake b/bsp/projects/microej/core/microej_core.cmake new file mode 100644 index 0000000..78d38df --- /dev/null +++ b/bsp/projects/microej/core/microej_core.cmake @@ -0,0 +1,16 @@ +include_guard() +message("microej/core component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + #${CMAKE_CURRENT_LIST_DIR}/src/cpuload.c + #${CMAKE_CURRENT_LIST_DIR}/src/cpuload_impl_FreeRTOS.c +${CMAKE_CURRENT_LIST_DIR}/src/device_natives.c +${CMAKE_CURRENT_LIST_DIR}/src/fault_handlers.c +${CMAKE_CURRENT_LIST_DIR}/src/hooks_FreeRTOS.c +${CMAKE_CURRENT_LIST_DIR}/src/LLBSP_NXP.c +${CMAKE_CURRENT_LIST_DIR}/src/LLMJVM_FreeRTOS.c +${CMAKE_CURRENT_LIST_DIR}/src/microej_main.c +${CMAKE_CURRENT_LIST_DIR}/src/microej_time_freertos.c +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) diff --git a/bsp/projects/microej/core/src/LLBSP_NXP.c b/bsp/projects/microej/core/src/LLBSP_NXP.c new file mode 100644 index 0000000..2c2d88f --- /dev/null +++ b/bsp/projects/microej/core/src/LLBSP_NXP.c @@ -0,0 +1,44 @@ +/* + * C + * + * Copyright 2014-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief Generic LLBSP implementation. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include + +#include "fsl_debug_console.h" +#include "LLBSP_impl.h" + +#ifdef __cplusplus + extern "C" { +#endif + +extern void SOAR_START(void); +extern void SOAR_END(void); + +#if defined(MICROEJ_MULTIAPP) +extern void _java_installed_features_text_start(void); +extern void _java_installed_features_text_size(void); +#endif // MICROEJ_MULTIAPP + + +/** + * @brief Writes the character c, cast to an unsigned char, to stdout stream. + * This function is used by the default implementation of the Java System.out. + */ +void LLBSP_IMPL_putchar(int32_t c){ + PUTCHAR(c); +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/core/src/LLMJVM_FreeRTOS.c b/bsp/projects/microej/core/src/LLMJVM_FreeRTOS.c new file mode 100644 index 0000000..e622afc --- /dev/null +++ b/bsp/projects/microej/core/src/LLMJVM_FreeRTOS.c @@ -0,0 +1,268 @@ +/* + * C + * + * Copyright 2018-2022 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + */ + +/** + * @file + * @brief LLMJVM implementation over FreeRTOS. + * @author MicroEJ Developer Team + * @version 1.1.0 + * @date 6 May 2021 + */ + +/* + * This implementation uses a dedicated hardware timer for time implementation, + * instead of internal FreeRTOS timer which is a 32bits timer. + */ + +/* Includes ------------------------------------------------------------------*/ +#include "misra_2004_conf.h" + +MISRA_2004_DISABLE_ALL +#include +#include +#include + +#include "LLMJVM_FreeRTOS_configuration.h" +#include FREERTOS_HEADER +#include FREERTOS_TIMERS_HEADER +#include FREERTOS_SEMPHR_HEADER +#include FREERTOS_TASK_HEADER + +#include "LLMJVM_impl.h" +#include "microej_time.h" +#include "sni.h" +MISRA_2004_ENABLE_ALL + +#ifdef __cplusplus + extern "C" { +#endif + +/* Defines -------------------------------------------------------------------*/ + +/* + * Useful macros and definitions + */ + +/* ID for the FreeRTOS Timer */ +#define WAKE_UP_TIMER_ID 42 + +/* Globals -------------------------------------------------------------------*/ + +/* + * Shared variables + */ +/* Absolute time in ms at which timer will be launched */ +static int64_t LLMJVM_FREERTOS_next_wake_up_time = INT64_MAX; + +/* Set to true when the timer expires, set to true when the timer is started. */ +volatile bool LLMJVM_FREERTOS_timer_expired = false; + +/* Timer for scheduling next alarm */ +static TimerHandle_t LLMJVM_FREERTOS_wake_up_timer; + +/* Binary semaphore to wakeup microJVM */ +static SemaphoreHandle_t LLMJVM_FREERTOS_Semaphore; + +/* Private functions ---------------------------------------------------------*/ + +static void wake_up_timer_callback(TimerHandle_t timer); + +/* + * Since LLMJVM_schedule() prototype does not match the timer callback prototype, + * we create a wrapper around it and check the ID of the timer. + */ +MISRA_2004_DISABLE_RULE_11_3 +static void wake_up_timer_callback(TimerHandle_t timer) { + uint32_t id = (uint32_t) pvTimerGetTimerID(timer); + if (id == (uint32_t)WAKE_UP_TIMER_ID) { + LLMJVM_FREERTOS_timer_expired = true; + LLMJVM_schedule(); + } +} +MISRA_2004_ENABLE_ALL + +/* Public functions ----------------------------------------------------------*/ + +/* + * Implementation of functions from LLMJVM_impl.h + * and other helping functions. + */ + +/* + * Creates the timer used to callback the LLMJVM_schedule() function. + * After its creation, the timer is idle. + */ +MISRA_2004_DISABLE_RULE_11_3 +int32_t LLMJVM_IMPL_initialize(void) { + int32_t result = LLMJVM_OK; + /* Create a timer to schedule an alarm for the VM */ + LLMJVM_FREERTOS_wake_up_timer = xTimerCreate(NULL, (TickType_t )100, (UBaseType_t)pdFALSE, + (void*) WAKE_UP_TIMER_ID, wake_up_timer_callback); + + if (LLMJVM_FREERTOS_wake_up_timer == NULL) { + result = LLMJVM_ERROR; + } else { + LLMJVM_FREERTOS_Semaphore = xSemaphoreCreateBinary(); + + if (LLMJVM_FREERTOS_Semaphore == NULL) { + result = LLMJVM_ERROR; + } else { + /* Created semaphore is in an empty state meaning that + it must first be given before it can be taken. */ + xSemaphoreGive(LLMJVM_FREERTOS_Semaphore); + microej_time_init(); + } + } + return result; +} +MISRA_2004_ENABLE_ALL + +/* + * Once the task is started, save a handle to it. + */ +int32_t LLMJVM_IMPL_vmTaskStarted(void) { + return LLMJVM_OK; +} + +/* + * Schedules requests from the VM + */ +int32_t LLMJVM_IMPL_scheduleRequest(int64_t absoluteTime) { + int32_t result = LLMJVM_OK; + int64_t currentTime, relativeTime, relativeTick; + portBASE_TYPE xTimerChangePeriodResult, xTimerStartResult; + + currentTime = LLMJVM_IMPL_getCurrentTime(JTRUE); + + relativeTime = absoluteTime - currentTime; + /* Determine relative time/tick */ + relativeTick = microej_time_time_to_tick(relativeTime); + + if (relativeTick <= 0) { + /* 'absoluteTime' has been reached yet */ + + /* No pending request anymore */ + LLMJVM_FREERTOS_next_wake_up_time = INT64_MAX; + + /* Stop current timer (no delay) */ + xTimerStop(LLMJVM_FREERTOS_wake_up_timer, (TickType_t )0); + + /* Notify the VM now */ + result = LLMJVM_schedule(); + } else if ((LLMJVM_FREERTOS_timer_expired == true) + || (absoluteTime < LLMJVM_FREERTOS_next_wake_up_time) + || (LLMJVM_FREERTOS_next_wake_up_time <= currentTime)) { + /* We want to schedule a request in the future but before the existing request + or the existing request is already done */ + + /* Save new alarm absolute time */ + LLMJVM_FREERTOS_next_wake_up_time = absoluteTime; + + /* Stop current timer (no delay) */ + xTimerStop(LLMJVM_FREERTOS_wake_up_timer, (TickType_t )0); + LLMJVM_FREERTOS_timer_expired = false; + + /* Schedule the new alarm */ + xTimerChangePeriodResult = xTimerChangePeriod(LLMJVM_FREERTOS_wake_up_timer, (TickType_t)relativeTick, (TickType_t)0); + xTimerStartResult = xTimerStart(LLMJVM_FREERTOS_wake_up_timer, (TickType_t )0); + + if ((xTimerChangePeriodResult != pdPASS) + || (xTimerStartResult != pdPASS)) { + result = LLMJVM_ERROR; + } + } else { + /* else: there is a pending request that will occur before the new one -> do nothing */ + } + + return result; +} + +/* + * Suspends the VM task if the pending flag is not set + */ +int32_t LLMJVM_IMPL_idleVM(void) { + portBASE_TYPE res = xSemaphoreTake(LLMJVM_FREERTOS_Semaphore, + portMAX_DELAY); + + return (res == pdTRUE) ? (int32_t) LLMJVM_OK : (int32_t) LLMJVM_ERROR; +} + +/* + * Wakes up the VM task + */ +MISRA_2004_DISABLE_RULE_10_6 +MISRA_2004_DISABLE_RULE_11_3 +MISRA_2004_DISABLE_RULE_14_3 +int32_t LLMJVM_IMPL_wakeupVM(void) { + portBASE_TYPE res; + + if (IS_INSIDE_INTERRUPT()) { + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + res = xSemaphoreGiveFromISR(LLMJVM_FREERTOS_Semaphore, + &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken != pdFALSE) { + /* Force a context switch here. */ + YIELD_FROM_ISR(xHigherPriorityTaskWoken); + } + } else { + res = xSemaphoreGive(LLMJVM_FREERTOS_Semaphore); + } + + return (res == pdTRUE) ? (int32_t) LLMJVM_OK : (int32_t) LLMJVM_ERROR; +} +MISRA_2004_ENABLE_ALL + +/* + * Clear the pending wake up flag and reset next wake up time + */ +int32_t LLMJVM_IMPL_ackWakeup(void) { + return LLMJVM_OK; +} + +/* + * Gets the system or the application time in milliseconds + */ +MISRA_2004_DISABLE_RULE_11_3 +int32_t LLMJVM_IMPL_getCurrentTaskID(void) { + return (int32_t) xTaskGetCurrentTaskHandle(); +} +MISRA_2004_ENABLE_ALL + +/* + * Sets the application time + */ +void LLMJVM_IMPL_setApplicationTime(int64_t t) { + microej_time_set_application_time(t); +} + +/* + * Gets the system or the application time in milliseconds + */ +MISRA_2004_DISABLE_RULE_16_4 +int64_t LLMJVM_IMPL_getCurrentTime(uint8_t sys) { + return microej_time_get_current_time(sys); +} +MISRA_2004_ENABLE_ALL + +/* + * Gets the system time in nanoseconds + */ +int64_t LLMJVM_IMPL_getTimeNanos(void) { + return microej_time_get_time_nanos(); +} + +/* + * Shuts the system down + */ +int32_t LLMJVM_IMPL_shutdown(void) { + return LLMJVM_OK; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/core/src/cpuload.c b/bsp/projects/microej/core/src/cpuload.c new file mode 100644 index 0000000..56a14a6 --- /dev/null +++ b/bsp/projects/microej/core/src/cpuload.c @@ -0,0 +1,125 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* Includes ------------------------------------------------------------------*/ + +#include "cpuload_impl.h" + +#include +#include "fsl_debug_console.h" +#include "wm_os.h" +/* Globals -------------------------------------------------------------------*/ + +#ifdef CPULOAD_ENABLED +static volatile uint32_t cpuload_schedule_time; +static volatile uint32_t cpuload_last_load; +static volatile uint32_t cpuload_reference_counter; +static volatile uint32_t cpuload_idle_counter; +static volatile uint32_t cpuload_ask_counter; +#endif + +/* API -----------------------------------------------------------------------*/ + +void cpuload_idle(void) +{ +#ifdef CPULOAD_ENABLED + __disable_irq(); + cpuload_idle_counter++; + __enable_irq(); +#endif +} + + +int32_t cpuload_init(void) +{ +#ifdef CPULOAD_ENABLED + + // get reference time (must be done before creating task) + cpuload_impl_start_idle_task(); + cpuload_impl_sync_os_tick(); + cpuload_idle_counter = 0; + os_setup_idle_function(cpuload_idle); + cpuload_impl_sleep(CPULOAD_SCHEDULE_TIME/10); + + if (cpuload_idle_counter == 0){ + // it is an error: this counter must have been updated + // during the previous sleep. + PRINTF("CPU load startup: invalid idle counter value: %ld\n", cpuload_idle_counter); + return CPULOAD_INVALID_COUNTER; + } + + // fix globals + cpuload_schedule_time = CPULOAD_SCHEDULE_TIME; + cpuload_reference_counter = (cpuload_idle_counter*10)+5; + cpuload_idle_counter = 0; + cpuload_last_load = 0; + cpuload_ask_counter = 0; + + // create task + if (cpuload_impl_start_task() != 0) + { + // an error has occurred + return CPULOAD_START_TASK_ERROR; + } + + return CPULOAD_OK; + +#else + return CPULOAD_NOT_ENABLED; +#endif +} + +uint32_t cpuload_get(void) +{ +#ifdef CPULOAD_ENABLED + uint32_t ret = cpuload_last_load; + // clear average + cpuload_ask_counter = 0; + return ret; +#else + return 0; +#endif +} + +void cpuload_task(void) +{ +#ifdef CPULOAD_ENABLED + while(1) + { + // sleep during n milliseconds + cpuload_impl_sleep(cpuload_schedule_time); + + // save global variables into local ones as they are volatile and might change while computing the average + uint32_t cpuload_last_load_tmp = cpuload_last_load; + uint32_t cpuload_reference_counter_tmp = cpuload_reference_counter; + uint32_t cpuload_idle_counter_tmp = cpuload_idle_counter; + uint32_t cpuload_ask_counter_tmp = cpuload_ask_counter; + + // average computing + uint32_t average_compute = cpuload_last_load_tmp * cpuload_ask_counter_tmp; + uint32_t last_average = 100 - ((100 * cpuload_idle_counter_tmp) / cpuload_reference_counter_tmp); + cpuload_ask_counter++; + cpuload_last_load = (average_compute + last_average) / cpuload_ask_counter; + + // reset cpuload counter + cpuload_idle_counter = 0; + } +#endif +} + + +/* Java API ------------------------------------------------------------------*/ + +uint32_t javaCPULoadInit(void) +{ + return cpuload_init(); +} + +uint32_t javaCPULoadGet(void) +{ + return cpuload_get(); +} diff --git a/bsp/projects/microej/core/src/cpuload_impl_FreeRTOS.c b/bsp/projects/microej/core/src/cpuload_impl_FreeRTOS.c new file mode 100644 index 0000000..69950ae --- /dev/null +++ b/bsp/projects/microej/core/src/cpuload_impl_FreeRTOS.c @@ -0,0 +1,66 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * Implementation for FreeRTOS + */ + +#include "cpuload_conf.h" +#ifdef CPULOAD_ENABLED + +/* Includes ------------------------------------------------------------------*/ + +#include "FreeRTOS.h" +#include "task.h" +#include "cpuload_impl.h" + +#if (configUSE_IDLE_HOOK == 0) + #error configUSE_IDLE_HOOK must be defined in FreeRTOSConfig.h and equals to 1 when CPULOAD_ENABLED defined. +#endif + +/* Globals -------------------------------------------------------------------*/ + +#define CPULOAD_STACK_SIZE ( 512 ) +#define CPULOAD_TASK_PRIORITY ( 15 ) +#define CPULOAD_TASK_STACK_SIZE CPULOAD_STACK_SIZE/4 + +/* Private API ---------------------------------------------------------------*/ + +static void _cpuload_task(void * pvParameters) +{ + // launch cpuload job + cpuload_task(); + // job end, cleanup resources + vTaskDelete(xTaskGetCurrentTaskHandle()); +} + +/* API -----------------------------------------------------------------------*/ + +int32_t cpuload_impl_start_idle_task(void) +{ + return 0; // nothing to do (no error) +} + +int32_t cpuload_impl_start_task(void) +{ + BaseType_t xReturn = xTaskCreate( _cpuload_task, "CPULOAD", CPULOAD_TASK_STACK_SIZE, NULL, CPULOAD_TASK_PRIORITY, NULL ); + return xReturn == pdPASS ? 0 : -1; +} + +void cpuload_impl_sync_os_tick(void) +{ + TickType_t os_tick = xTaskGetTickCount(); + while(os_tick == xTaskGetTickCount()); +} + +void cpuload_impl_sleep(uint32_t ms) +{ + TickType_t ticks = ms / portTICK_PERIOD_MS; + vTaskDelay(ticks ? ticks : 1); /* Minimum delay = 1 tick */ +} + +#endif // CPULOAD_ENABLED diff --git a/bsp/projects/microej/core/src/device_natives.c b/bsp/projects/microej/core/src/device_natives.c new file mode 100644 index 0000000..4175d30 --- /dev/null +++ b/bsp/projects/microej/core/src/device_natives.c @@ -0,0 +1,19 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#define as_string_int(x) #x +#define as_string(x) as_string_int(x) + +uint32_t Java_ej_util_DeviceNatives_getId(uint8_t* buffer, int32_t length) +{ + static const char * board_name = as_string(SDK_BOARD_ID); + int how_many = (length < strlen(board_name)) ? (length) : (strlen(board_name)); + strncpy((char *)buffer, board_name, how_many); + return how_many; +} diff --git a/bsp/projects/microej/core/src/fault_handlers.c b/bsp/projects/microej/core/src/fault_handlers.c new file mode 100644 index 0000000..76cad7c --- /dev/null +++ b/bsp/projects/microej/core/src/fault_handlers.c @@ -0,0 +1,406 @@ +/* + * C + * + * Copyright 2014-2022 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + * + * Copyright 2024 NXP + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +/** + * @file fault_handlers.c + * + * @brief This file contains the fault exception handlers. + * + * @details The CMSIS names are used. + * + * There are two modes: + * - verbose + * - lite + * + * In verbose mode, each fault exception handler will: + * - print the stack frame, + * - print its name, + * - print the associated fault status register, + * - try to make an analysis of the fault cause, + * - make an infinite loop. + * + * In lite mode, each fault exception handler will: + * - print its name, + * - make an infinite loop. + * + * Define the @ref VERBOSE_MODE macro to activate verbose mode. + */ + +/* Includes ______________________________________________________________________*/ +#include +#include + +#include "fsl_debug_console.h" + +#include "fault_handlers.h" // will check prototypes and import public types + + +typedef struct __attribute__((packed)) ContextStateFrame { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t return_address; + uint32_t xpsr; +} sContextStateFrame; + + + +// NOTE: If you are using CMSIS, the registers can also be +// accessed through CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk +#define HALT_IF_DEBUGGING() \ + do { \ + if ((*(volatile uint32_t *)0xE000EDF0) & (1 << 0)) { \ + __asm("bkpt 1"); \ + } \ +} while (0) + +/* Macros ________________________________________________________________________*/ + +/** + * @brief Define this macro to if you are using Keil's ARMCC toolchain. If you are using IAR or GCC toolchains, do not define it. + */ +//#define COMPILE_WITH_ARMCC + +/** + * @brief Define this macro to enable verbose handlers. Verbose handlers will consume more memory than lite handlers. + */ +#define VERBOSE_MODE + +/** + * @brief Make an infinite while loop. + */ +#define INFINITE_LOOP() {while(1);} + +#ifdef VERBOSE_MODE +/** + * @brief This macro is called as the begining of each handlers to print the stack frame. + * + * @details There are two stack pointers in Cortex-M processors: + * - MSP (Main Stack Pointer) + * - PSP (Process Stack Pointer) + * When handling faults, we need to know which one was used before entering the faults so that + * we can retrieve interesting information. + * + * To do so, we need to test the value of EXC_RETURN, which is stored into LR during exception + * (see Section 8.1.4 EXC_RETURN). Then, we can fetch the correct stack pointer with the MRS instruction + * (MRS = Move from special register to general register). + * + * NOTE: IAR's compiler doesn't like then comments are interlaced with macro definition lines. + * Here is what the macro does: + * - Check if bit 2 (stack return) is set in EXC_RETURN / LR + * - If-Then condition instruction + * - If equals, store MSP in R0 + * - Else, store PSP in RO (1st parameter) + * - MSP is stored in R1 (2nd parameter) + * - PSP is stored in R2 (3rd parameter) + * - LR is stored in R3 (4th parameter) + * - Call C function for printing + */ +#if defined(__CC_ARM) +void printer(uint32_t current_sp, uint32_t msp, uint32_t psp, uint32_t exc_return); + +__asm void print_stacked_registers() +{ + TST LR, #4 + ITE EQ + MRSEQ R0, MSP + MRSNE R0, PSP + MRS R1, MSP + MRS R2, PSP + MOV R3, LR + LDR R4, =__cpp(printer) + BX R4 +} +#else +// Compatible with GCC and IAR +#define print_stacked_registers() {\ + __asm("TST LR, #4");\ + __asm("MRS R1, MSP");\ + __asm("MRS R2, PSP");\ + __asm("MOV R3, LR");\ + __asm("BL printer");\ +} +#endif + +// CMSIS doesn't provide macro to get bits from BFSR (which is the 2nd byte in CFSR), so we create our own macros +#define BFSR_IBUSERR_Pos (0) +#define BFSR_IBUSERR_Msk (1 << BFSR_IBUSERR_Pos) + +#define BFSR_PRECISERR_Pos (1) +#define BFSR_PRECISERR_Msk (1 << BFSR_PRECISERR_Pos) + +#define BFSR_IMPRECISERR_Pos (2) +#define BFSR_IMPRECISERR_Msk (1 << BFSR_IMPRECISERR_Pos) + +#define BFSR_BFARVALID_Pos (15) +#define BFSR_BFARVALID_Msk (1 << BFSR_BFARVALID_Pos) + +// CMSIS doesn't provide macro to get bits from UFSR (which is the upper half-word in CFSR), so we create our own macros +#define UFSR_UNDEFINSTR_Pos (0) +#define UFSR_UNDEFINSTR_Msk (1 << UFSR_UNDEFINSTR_Pos) + +#define UFSR_INVSTATE_Pos (1) +#define UFSR_INVSTATE_Msk (1 << UFSR_INVSTATE_Pos) + + +/* Global variables ___________________________________________________________*/ + + +/* Private types and variables ___________________________________________________*/ + + +/* Private functions ______________________________________________________________*/ +// WARNING: +/** + * @brief C function to print the stacked registers (== the stack frame) along with EXEC_RETURN. + * + * @warning this function cannot be static because it won't be seen by assembly code during link edition. + * You should not called this function directly. + */ +/*static*/ void printer(uint32_t current_sp, uint32_t msp, uint32_t psp, uint32_t exc_return) +{ + uint32_t *sp; + PRINTF("---------------------------------------------------------------------\n"); + // Show stack pointers + PRINTF("Current SP = %.8lX\n", current_sp); + PRINTF("MSP = %.8lX\n", msp); + PRINTF("PSP = %.8lX\n", psp); + PUTCHAR('\n'); + + // Show stacked registers == stack frame (see section 8.1.3 and figure 12.4) + sp = (uint32_t*) current_sp; + PRINTF("Stack frame:\n"); + PRINTF("R0 =\t%.8lX\n", *sp++); + PRINTF("R1 =\t%.8lX\n", *sp++); + PRINTF("R2 =\t%.8lX\n", *sp++); + PRINTF("R3 =\t%.8lX\n", *sp++); + PRINTF("R12 =\t%.8lX\n", *sp++); + PRINTF("LR =\t%.8lX\n", *sp++); + PRINTF("PC =\t%.8lX\n", *sp++); + PRINTF("xPSR =\t%.8lX\n", *sp++); + PUTCHAR('\n'); + + PRINTF("EXC_RETURN (LR) = %.8lX\n", exc_return); + + PRINTF("---------------------------------------------------------------------\n"); +} + + +#define HARDFAULT_HANDLING_ASM(_x) \ + __asm volatile( \ + "tst lr, #4 \n" \ + "ite eq \n" \ + "mrseq r0, msp \n" \ + "mrsne r0, psp \n" \ + "movw r1, #0xED00 \n" \ + "movt r1, #0xE000 \n" \ + "b my_fault_handler_c \n" \ + ) + + +// Disable optimizations for this function so "frame" argument +// does not get optimized away +#ifdef __ICCARM__ +#pragma optimize=none +#endif +#ifdef __GNUC__ +void __attribute__ ((noinline)) my_fault_handler_c(sContextStateFrame *frame, SCB_Type * scb) { +#else +void my_fault_handler_c(sContextStateFrame *frame, SCB_Type * scb) { +#endif + // If and only if a debugger is attached, execute a breakpoint + // instruction so we can take a look at what triggered the fault + HALT_IF_DEBUGGING(); + + uint32_t cfsr = SCB->CFSR; + uint32_t hfsr = SCB->HFSR; + uint32_t mmfar = SCB->MMFAR; + uint32_t bfar = SCB->BFAR; + PRINTF("HardFault:\n"); + PRINTF("SCB->CFSR 0x%08lx\n", cfsr); + PRINTF("SCB->HFSR 0x%08lx\n", hfsr); + PRINTF("SCB->MMFAR 0x%08lx\n", mmfar); + PRINTF("SCB->BFAR 0x%08lx\n", bfar); + PUTCHAR('\n'); + HALT_IF_DEBUGGING(); + INFINITE_LOOP(); + + // Logic for dealing with the exception. Typically: + // - log the fault which occurred for postmortem analysis + // - If the fault is recoverable, + // - clear errors and return back to Thread Mode + // - else + // - reboot system +} + + +/* Public functions _______________________________________________________________*/ + +/* + * @brief Hard Fault exception handler. + */ +void HardFault_Handler(void) +{ +/* uint32_t hfsr; + print_stacked_registers(); + PRINTF(__func__); + + hfsr = SCB->HFSR; + PRINTF("Hard Fault Status Register =\t%lX\n", hfsr); + + if(hfsr & SCB_HFSR_FORCED_Msk) + { + PRINTF("FORCED"); + } +*/ + HARDFAULT_HANDLING_ASM(); + INFINITE_LOOP(); +} + + +/* + * @brief Memory Management Fault exception handler. + */ +void MemFault_Handler (void) +{ + print_stacked_registers(); + PRINTF(__func__); + + INFINITE_LOOP(); +} + + +/* + * @brief Bus Fault exception handler. + */ +void BusFault_Handler (void) +{ + uint32_t cfsr; + uint8_t bfsr; + uint32_t bfar; + bool still_valid; + print_stacked_registers(); + PRINTF(__func__); + + cfsr = SCB->CFSR; + PRINTF("Configurable Fault Status Register =\t%.8lX\n", cfsr); + + bfsr = (cfsr & SCB_CFSR_BUSFAULTSR_Msk) >> SCB_CFSR_BUSFAULTSR_Pos; + PRINTF("Bus Fault Status Register =\t%.2X\n", bfsr); + + if(bfsr & BFSR_IBUSERR_Msk) + { + PRINTF("Instruction access error"); + // This case has not been experimented yet + } + + if(bfsr & BFSR_PRECISERR_Msk) + { + PRINTF("Precise data access error"); + + // Faulting instruction + // --> see the PC of the printed stack frame + + // Address of faulting data access + bfar = SCB->BFAR; + PRINTF("Address of faulting data access (BFAR) = %.8lX\n", bfar); + + still_valid = (cfsr & BFSR_BFARVALID_Msk); + if(!still_valid) + { + PRINTF("WARNING: BFAR is no longer valid!"); + } + } + + if(bfsr & BFSR_IMPRECISERR_Msk) + { + PRINTF("Imprecise data access error"); + } + + INFINITE_LOOP(); +} + + +/* + * @brief Usage Fault exception handler. + */ +void UsageFault_Handler (void) +{ + uint32_t cfsr; + uint16_t ufsr; + // TODO Activate usage for for division by 0 and unaligned access? (see page 384) + + print_stacked_registers(); + PRINTF(__func__); + + cfsr = SCB->CFSR; + PRINTF("Configurable Fault Status Register =\t%lX\n", cfsr); + + ufsr = (cfsr & SCB_CFSR_USGFAULTSR_Msk) >> SCB_CFSR_USGFAULTSR_Pos; + PRINTF("Usage Fault Status Register =\t%X\n", ufsr); + + if(ufsr & UFSR_UNDEFINSTR_Msk) + { + PRINTF("Attempt to execute an undefined instruction"); + } + + if(ufsr & UFSR_INVSTATE_Msk) + { + PRINTF("Attempt to switch to invalid mode (like ARM state)"); + } + + INFINITE_LOOP(); +} +#else +/* + * @brief Hard Fault exception handler. + */ +void HardFault_Handler (void) +{ + PRINTF(__func__); + INFINITE_LOOP(); +} + + +/* + * @brief Memory Management Fault exception handler. + */ +void MemFault_Handler (void) +{ + PRINTF(__func__); + INFINITE_LOOP(); +} + + +/* + * @brief Bus Fault exception handler. + */ +void BusFault_Handler (void) +{ + PRINTF(__func__); + INFINITE_LOOP(); +} + + +/* + * @brief Usage Fault exception handler. + */ +void UsageFault_Handler (void) +{ + PRINTF(__func__); + INFINITE_LOOP(); +} + +#endif diff --git a/bsp/projects/microej/core/src/hooks_FreeRTOS.c b/bsp/projects/microej/core/src/hooks_FreeRTOS.c new file mode 100644 index 0000000..7202907 --- /dev/null +++ b/bsp/projects/microej/core/src/hooks_FreeRTOS.c @@ -0,0 +1,56 @@ +/* + * C + * + * Copyright 2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * This file implements the application hooks functions needed by FreeRTOS. + * These functions trace problems that occurs during execution. + * Their names are defined by FreeRTOS + * and must be implemented (here) or desactivated (in FreeRTOSConfig.h). + * + * See "Hook Functions [More Advanced]" on FreeRTOS Website. + * http://www.freertos.org/a00016.hmtl + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include + +/* FreeRTOS kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Freescale includes. */ +#include "fsl_debug_console.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* Public functions ----------------------------------------------------------*/ + +void vApplicationStackOverflowHook(TaskHandle_t xTask, char * pcTaskName) { + if (pcTaskName != NULL) { + PRINTF("A stack overflow had occurred in task \"%s\"\n", pcTaskName); + } else { + PRINTF("A stack overflow had occurred in task\n"); + } + + while(1) + {} // Trap when a stack overflow occurs +} + +void vApplicationMallocFailedHook(void) { + PRINTF("A malloc fail had occurred\n"); + + while(1) + {} // Trap when a call to malloc fails +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/core/src/microej_main.c b/bsp/projects/microej/core/src/microej_main.c new file mode 100644 index 0000000..862cee0 --- /dev/null +++ b/bsp/projects/microej/core/src/microej_main.c @@ -0,0 +1,66 @@ +/* + * C + * + * Copyright 2020-2022 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + * + */ + +/** + * @file + * @brief MicroEJ startup. + * @author MicroEJ Developer Team + * @version 2.0.0 + * @date 15 September 2020 + */ + +#include "fsl_debug_console.h" +#include "microej_main.h" +#include "LLMJVM.h" +#include "sni.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Creates and starts a MicroEJ instance. This function returns when the MicroEJ execution ends. + */ +void microej_main(int argc, char **argv) { + void* vm; + int32_t err; + int32_t exitcode; + + // create VM + vm = SNI_createVM(); + + if (vm == NULL) { + PRINTF("MicroEJ initialization error.\n"); + } else { + PRINTF("MicroEJ START\n"); + + // Error codes documentation is available in LLMJVM.h + err = SNI_startVM(vm, argc, argv); + + if (err < 0) { + // Error occurred + if (err == LLMJVM_E_EVAL_LIMIT) { + PRINTF("Evaluation limits reached.\n"); + } else { + PRINTF("MicroEJ execution error (err = %d).\n", (int) err); + } + } else { + // VM execution ends normally + exitcode = SNI_getExitCode(vm); + PRINTF("MicroEJ END (exit code = %d)\n", (int) exitcode); + } + + // delete VM + SNI_destroyVM(vm); + } +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/core/src/microej_time_freertos.c b/bsp/projects/microej/core/src/microej_time_freertos.c new file mode 100644 index 0000000..8c7ffbb --- /dev/null +++ b/bsp/projects/microej/core/src/microej_time_freertos.c @@ -0,0 +1,143 @@ +/* + * C + * + * Copyright 2018-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** +* @file +* @brief MicroEJ Time APIs implementation for FreeRTOS. +* @author MicroEJ Developer Team +* @version 0.1.0 +*/ + + #define portTickType TickType_t +#include + +#include "microej_time_freertos_configuration.h" +#include "microej_time.h" + +#include FREERTOS_HEADER +#include FREERTOS_TASK_HEADER + +#ifdef __cplusplus + extern "C" { +#endif + +#define MICROSECONDS_PER_TICK (1000000 / configTICK_RATE_HZ) // Number of microseconds per tick. +#define MILLISECONDS_PER_TICK (1000 / configTICK_RATE_HZ); // Number of milliseconds per tick. +#define MILLISECONDS_TO_MICROSECONDS (1000) // Converts milliseconds to microseconds. +#define MILLISECONDS_TO_NANOSECONDS (1000000) // Converts milliseconds to nanoseconds. + +#define TRUE (1) +#define FALSE (0) + +#if ( configUSE_TICKLESS_IDLE != 0 ) + +// This implementation is not compatible with the tickless mode of FreeRTOS because +// the tick counter will not be incremented correctly when the system sleeps. +#error "OS Tickless mode not managed by this implementation" + +#endif + +/** Offset in milliseconds from system time to application time. */ +static uint64_t microej_application_time_offset = 0; + +/** + * @brief Initialisation of the timebase used by MicroEJ. Initialize in this function everything that is needed to implement the API. + * + */ +void microej_time_init(void) { + /* Nothing to do here. */ +} + +/** + * @brief Converts a time in milliseconds to a number of system ticks. + * The result is round up to the next tick (ie. converting back the resulting ticks to milliseconds results in a value greater than or equals to given time). + * If an overflow occurs during the time conversion, a saturated number of ticks is returned. + * + * @param time the time to convert in milliseconds, + * @return int64_t the number of ticks. + */ + +int64_t microej_time_time_to_tick(int64_t time) { + if (time < 0) { + return 0; + } + + int64_t time_microseconds = time * MILLISECONDS_TO_MICROSECONDS; + + // Check for no overflow + if (time_microseconds >= 0) { + int64_t ticks64 = (time_microseconds + (MICROSECONDS_PER_TICK-1)) / MICROSECONDS_PER_TICK; + + // Check for no overflow + if (ticks64 >= 0) { + portTickType ticks = (portTickType)ticks64; + + // Check for no overflow + if (ticks == ticks64) { + return (int64_t)ticks; + } + } + } + + // An overflow occurs: saturate the value to the max value for a portTickType + return (int64_t)portMAX_DELAY; +} + +/** + * @brief Converts a number of system ticks in milliseconds. + * If an overflow occurs during the conversion, a saturated number of milliseconds is returned. + * @param ticks the number of ticks to convert in milliseconds, + * @return int64_t the time in milliseconds. + */ +int64_t microej_time_tick_to_time(int64_t ticks) { + if(ticks < 0){ + return 0; + } + int64_t time_milliseconds = ticks * MILLISECONDS_PER_TICK; + // Check for no overflow + if(time_milliseconds < 0){ + // An overflow occurs: saturate the value to int64_t max value + return INT64_MAX; + } + return time_milliseconds; +} + +/** + * @brief Gets the current platform or application time. + * + * @param is_platform_time set to 1 to get the platform time or set to 0 to get the time elapsed since midnight, January 1, 1970 UTC. + * @return int64_t the time in milliseconds. + */ +int64_t microej_time_get_current_time(uint8_t is_platform_time) { + int64_t ticks = (int64_t) xTaskGetTickCount(); + int64_t time = microej_time_tick_to_time(ticks); + + if (is_platform_time == TRUE) { + return time; + } else { + int64_t applicationTime = time + microej_application_time_offset; + return applicationTime; + } +} + +int64_t microej_time_get_time_nanos() { + return microej_time_get_current_time(TRUE) * MILLISECONDS_TO_NANOSECONDS; +} + +/** + * @brief Sets the application time. + * + * @param time value in milliseconds of the time elapsed since midnight, January 1, 1970 UTC. + */ +void microej_time_set_application_time(int64_t time) { + int64_t currentTime = (int64_t) microej_time_get_current_time(TRUE); + microej_application_time_offset = time - currentTime; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/ecom-network-lwip/inc/ecom_network_lwip_configuration.h b/bsp/projects/microej/ecom-network-lwip/inc/ecom_network_lwip_configuration.h new file mode 100644 index 0000000..c6962bf --- /dev/null +++ b/bsp/projects/microej/ecom-network-lwip/inc/ecom_network_lwip_configuration.h @@ -0,0 +1,93 @@ +/* + * C + * + * Copyright 2020-2021 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + * + */ + +#ifndef ECOM_NETWORK_LWIP_CONFIGURATION_H +#define ECOM_NETWORK_LWIP_CONFIGURATION_H + +/** + * @file + * @brief LLECOM_NETWORK over LWIP configuration. + * @author MicroEJ Developer Team + * @version 1.1.1 + * @date 21 April 2021 + */ + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Compatibility sanity check value. + * This define value is checked in the implementation to validate that the version of this configuration + * is compatible with the implementation. + * + * This value must not be changed by the user of the CCO. + * This value must be incremented by the implementor of the CCO when a configuration define is added, deleted or modified. + */ +#define ECOM_NETWORK_LWIP_CONFIGURATION_VERSION (1) + +/** + * @brief Provide here LLECOM_NETWORK_start and LLECOM_NETWORK_stop functions + * from interface driver which will allow to start and stop the interface + * Example: + * bool MY_WIFI_DRIVER_start_f(void); + * bool MY_WIFI_DRIVER_stop_f(void); + * #define LLECOM_NETWORK_start MY_WIFI_DRIVER_start_f + * #define LLECOM_NETWORK_stop MY_WIFI_DRIVER_stop_f + * Remove below line after once you define LLECOM_NETWORK_start and LLECOM_NETWORK_stop functions. + */ +//#error "Define here the LLECOM_NETWORK_start and LLECOM_NETWORK_stop functions for the network interface used (Wifi, Modem, Eth...) " +uint32_t start_f(void) {return 1;} +uint32_t stop_f(void) {return 1;} +#define LLECOM_NETWORK_start (start_f) +#define LLECOM_NETWORK_stop (stop_f) + +/** + * @brief Provide here LLECOM_NETWORK_apply_configuration function + * from interface driver side which will handle additional needed steps after an IP configuration was defined. + * An example can be to handle start/stop of DHCP client. + * + * Example: + * bool MY_WIFI_DRIVER_apply_configuration_f(struct netif* interface, bool is_static, ip_addr_t ip, ip_addr_t netmask, ip_addr_t gw); + * #define LLECOM_NETWORK_apply_configuration MY_WIFI_DRIVER_apply_configuration_f + * Remove below line after once you define LLECOM_NETWORK_apply_configuration function. + */ +//#error "Define here LLECOM_NETWORK_apply_configuration function to complete IP configuration process" +uint32_t apply_configuration_f(void * a,...) {return 1;} +#define LLECOM_NETWORK_apply_configuration (apply_configuration_f) +/** + * @brief Provide here LLECOM_NETWORK_interface_is_started function + * from interface driver side which will return the running state of the network interface. + * + * Example: + * bool MY_WIFI_DRIVER_interface_is_started_f(struct netif * interface); + * #define LLECOM_NETWORK_interface_is_started MY_WIFI_DRIVER_interface_is_started_f + * Remove below line after once you define LLECOM_NETWORK_interface_is_started function. + */ +//#error "Define here LLECOM_NETWORK_interface_is_started function to provide access to interface running status" +uint32_t interface_is_started_f(void * a) {return 1;} +#define LLECOM_NETWORK_interface_is_started (interface_is_started_f) + +/** + * @brief Set this define to print debug traces. + */ +//#define LLECOM_NETWORK_DEBUG + +#ifdef LLECOM_NETWORK_DEBUG +#include "fsl_debug_console.h" +#define LLECOM_NETWORK_DEBUG_TRACE PRINTF("[DEBUG] ");PRINTF +#else +#define LLECOM_NETWORK_DEBUG_TRACE(...) ((void) 0) +#endif + +#ifdef __cplusplus + } +#endif + +#endif // ECOM_NETWORK_LWIP_CONFIGURATION_H diff --git a/bsp/projects/microej/ecom-network-lwip/microej_ecom-network-lwip.cmake b/bsp/projects/microej/ecom-network-lwip/microej_ecom-network-lwip.cmake new file mode 100644 index 0000000..ec02d30 --- /dev/null +++ b/bsp/projects/microej/ecom-network-lwip/microej_ecom-network-lwip.cmake @@ -0,0 +1,11 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: BSD-3-Clause + +include_guard() +message("microej/ecom-network-lwip component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/ecom_network_helper_lwip.c +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) \ No newline at end of file diff --git a/bsp/projects/microej/ecom-network-lwip/src/ecom_network_helper_lwip.c b/bsp/projects/microej/ecom-network-lwip/src/ecom_network_helper_lwip.c new file mode 100644 index 0000000..cffd62b --- /dev/null +++ b/bsp/projects/microej/ecom-network-lwip/src/ecom_network_helper_lwip.c @@ -0,0 +1,578 @@ +/* + * C + * + * Copyright 2020-2021 MicroEJ Corp. All rights reserved. + * This library is provided in source code for use, modification and test, subject to license terms. + * Any modification of the source code will break MicroEJ Corp. warranties on the whole library. + * + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * @brief LLECOM_NETWORK implementation over LWIP. + * @author MicroEJ Developer Team + * @version 1.1.1 + * @date 21 April 2021 + */ + +#include +#include +#include "ecom_network_lwip_configuration.h" +#include "ecom_network_helper.h" +#include "microej_async_worker.h" +#include "LLECOM_NETWORK_impl.h" +#include "lwip/netif.h" +#include "lwip/ip.h" +#include "lwip/dns.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Sanity check between the expected version of the configuration and the actual version of + * the configuration. + * If an error is raised here, it means that a new version of the CCO has been installed and + * the configuration ecom_network_lwip_configuration.h must be updated based on the one provided + * by the new CCO version. + */ +#if ECOM_NETWORK_LWIP_CONFIGURATION_VERSION != 1 + + #error "Version of the configuration file ecom_network_lwip_configuration.h is not compatible with this implementation." + +#endif + +/* global to know if configuration is static or dhcp */ +static int8_t ecom_network_is_static; + +extern uint8_t dns_servers_list_updated; + +void LLECOM_NETWORK_IMPL_enable_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + netif_set_up(interface); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] interface enabled with result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_disable_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + netif_set_down(interface); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] interface disabled with result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_isEnabled_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + param->result = netif_is_up(interface) ? IF_STATE_ENABLED : IF_STATE_NOT_ENABLED; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_start_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + if (LLECOM_NETWORK_start()) { + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "Network driver error"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] interface started with result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_stop_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + if (LLECOM_NETWORK_stop()) { + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "Network driver error"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] interface stopped with result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_isStarted_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + + struct netif *pnetif = netif_find((char *)param->netifName); + if(pnetif != NULL){ + if (LLECOM_NETWORK_interface_is_started(pnetif) == 1) + param->result = IF_STATE_STARTED; + else + param->result = IF_STATE_NOT_STARTED; + } else { + param->result = IF_STATE_NOT_STARTED; + + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_getDNSCount_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + int32_t count = 0; + + for (int32_t i = 0; i < DNS_MAX_SERVERS; i++) { + const ip_addr_t* dns_addr = dns_getserver(i); + + // check if the DNS server IP address is right + if (!ip_addr_isany(dns_addr)) { + count++; + } else { + break; + } + } + + param->result = count; + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] DNS counted : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_getDNS_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_dns_context_t* param = (ECOM_NETWORK_dns_context_t*) job->params; + + if ((param->netifName == NULL) || (param->address == NULL) || (param->index < 0) || (param->index >= DNS_MAX_SERVERS)) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer or wrong index"; + } + } else { + const ip_addr_t* dns_addr = dns_getserver(param->index); + + // check if the DNS server IP address is right + if (!ip_addr_isany(dns_addr)) { + memcpy(param->address, ip_2_ip4(dns_addr), sizeof(ip4_addr_t)); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "DNS server IP address is not valid"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] get DNS result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_getGateway_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_ip_context_t* param = (ECOM_NETWORK_ip_context_t*) job->params; + + if ((param->netifName == NULL) || (param->address == NULL)) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + ip4_addr_set_u32((ip4_addr_t*)(param->address), *(u32_t*)netif_ip4_gw(interface)); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] get gateway result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_getNetmask_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_ip_context_t* param = (ECOM_NETWORK_ip_context_t*) job->params; + + if ((param->netifName == NULL) || (param->address == NULL)) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + ip4_addr_set_u32((ip4_addr_t*)(param->address), *(u32_t*)netif_ip4_netmask(interface)); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] get netmask result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_getIP_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_ip_context_t* param = (ECOM_NETWORK_ip_context_t*) job->params; + + if ((param->netifName == NULL) || (param->address == NULL)) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + ip4_addr_set_u32((ip4_addr_t*)(param->address), *(u32_t*)netif_ip4_addr(interface)); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] get ip address result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_isDNSStatic_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + param->result = (ecom_network_is_static == 0) ? IF_DNS_NOT_STATIC : IF_DNS_STATIC; + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] is static DNS result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_isStatic_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + param->result = (ecom_network_is_static == 0) ? IF_IP_DYNAMIC : IF_IP_STATIC; + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] is static IP result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_startConfiguration_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + param->result = 0; + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] configuration started with result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_endConfiguration_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_netif_context_t* param = (ECOM_NETWORK_netif_context_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + if (LLECOM_NETWORK_apply_configuration(interface, ecom_network_is_static, *netif_ip4_addr(interface), *netif_ip4_netmask(interface), *netif_ip4_gw(interface))) { + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "Network driver error"; + } + } + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] configuration ended with result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_setDNS_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_dns_context_t* param = (ECOM_NETWORK_dns_context_t*) job->params; + + if ((param->netifName == NULL) || (param->address == NULL) || (param->index < 0) || (param->index >= DNS_MAX_SERVERS)) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer or wrong index"; + } + } else { + dns_setserver((u8_t)param->index, (ip_addr_t*)(param->address)); + dns_servers_list_updated = 1; + param->result = 0; + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] set DNS result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_setGateway_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_ip_context_t* param = (ECOM_NETWORK_ip_context_t*) job->params; + + if ((param->netifName == NULL) || (param->address == NULL)) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + netif_set_gw(interface, (ip4_addr_t*)(param->address)); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] set gateway result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_setIP_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_ip_context_t* param = (ECOM_NETWORK_ip_context_t*) job->params; + + if ((param->netifName == NULL) || (param->address == NULL)) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + netif_set_ipaddr(interface, (ip4_addr_t*)(param->address)); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] set ip address result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_setNetmask_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_ip_context_t* param = (ECOM_NETWORK_ip_context_t*) job->params; + + if ((param->netifName == NULL) || (param->address == NULL)) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + struct netif* interface; + + interface = netif_find((char *)param->netifName); + + if (interface != NULL) { + netif_set_netmask(interface, (ip4_addr_t*)(param->address)); + param->result = 0; + } else { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "interface not found"; + } + } + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] set netmask result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_useDHCP_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_ip_config_t* param = (ECOM_NETWORK_ip_config_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + ecom_network_is_static = (param->use == JTRUE) ? 0 : 1; + param->result = 0; + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] use DHCP result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_useStaticDNS_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + ECOM_NETWORK_ip_config_t* param = (ECOM_NETWORK_ip_config_t*) job->params; + + if (param->netifName == NULL) { + param->result = -1; + if (param->error_message != NULL) { + param->error_message = "null pointer"; + } + } else { + if ((param->use == JTRUE) && !ecom_network_is_static) { + LLECOM_NETWORK_DEBUG_TRACE("WARNING: a statically set DNS address will be overridden by DHCP when joining a network"); + } + if ((param->use == JFALSE) && ecom_network_is_static) { + LLECOM_NETWORK_DEBUG_TRACE("WARNING: a dynamically set DNS address will have no effect until enabling the DHCP"); + } + param->result = 0; + } + + LLECOM_NETWORK_DEBUG_TRACE("[%s:%u] use static DNS result : %d (err %d)\n", __func__, __LINE__, param->result, param->error_code); +} + +void LLECOM_NETWORK_IMPL_setDefault_action(MICROEJ_ASYNC_WORKER_job_t* job) { + /* No action needed as LwIP handles intrinsically multiple network interfaces, + * just is needed to define this function for keep the compatibility with the new feaure of Ecom-Nertwork generic CCO. */ +} + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/ecom-network/inc/LLECOM_NETWORK.h b/bsp/projects/microej/ecom-network/inc/LLECOM_NETWORK.h new file mode 100644 index 0000000..c34b554 --- /dev/null +++ b/bsp/projects/microej/ecom-network/inc/LLECOM_NETWORK.h @@ -0,0 +1,33 @@ +/* + * C + * + * Copyright 2020-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef LLECOM_NETWORK_H +#define LLECOM_NETWORK_H + +/** + * @file + * @brief ECOM-NETWORK exported interface. + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 13 February 2023 + */ + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief High level interface used for generic ecom-network module initialization. + * It initializes internal components, like the worker and the helper. + */ +void LLECOM_NETWORK_initialize(void); + +#ifdef __cplusplus + } +#endif + +#endif /* LLECOM_NETWORK_H */ diff --git a/bsp/projects/microej/ecom-network/inc/ecom_network_configuration.h b/bsp/projects/microej/ecom-network/inc/ecom_network_configuration.h new file mode 100644 index 0000000..e78fdde --- /dev/null +++ b/bsp/projects/microej/ecom-network/inc/ecom_network_configuration.h @@ -0,0 +1,110 @@ +/* + * C + * + * Copyright 2020-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef ECOM_NETWORK_CONFIGURATION_H +#define ECOM_NETWORK_CONFIGURATION_H + +/** + * @file + * @brief LLECOM_NETWORK configuration. + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 13 February 2023 + */ + +#include "microej_async_worker.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//#error "This header must be customized with platform specific configuration. Remove this #error when done. This file is not modified when a new version of the CCO is installed." + +/** + * @brief Compatibility sanity check value. + * This define value is checked in the implementation to validate that the version of this configuration + * is compatible with the implementation. + * + * This value must not be changed by the user of the CCO. + * This value must be incremented by the implementor of the CCO when a configuration define is added, deleted or modified. + */ +#define ECOM_NETWORK_CONFIGURATION_VERSION (2) + +/** + * @brief Use this macro to define the initialization function of the network stack. + * Called from LLECOM_NETWORK_initialize(). + * By default this macro does nothing. + */ +#define llecom_network_init() ((void)0) + +/** + * @brief Set this define to use a custom worker to handle ECOM-NETWORK asynchronous jobs. + */ +//#define ECOM_NETWORK_CUSTOM_WORKER + +/** + * @brief Define ECOM-NETWORK custom or module specific worker. + */ +#ifdef ECOM_NETWORK_CUSTOM_WORKER +extern MICROEJ_ASYNC_WORKER_handle_t my_custom_worker; +#define ecom_network_worker my_custom_worker +#else +extern MICROEJ_ASYNC_WORKER_handle_t ecom_network_worker; +#endif + +/** + * @brief Number of workers dedicated to the ECOM-NETWORK in async_worker. + */ +#define ECOM_NETWORK_WORKER_JOB_COUNT (4) + +/** + * @brief Size of the waiting list for ECOM-NETWORK jobs in async_worker. + */ +#define ECOM_NETWORK_WAITING_LIST_SIZE (16) + +/** + * @brief Size of the ECOM-NETWORK stack in bytes. + */ +#define ECOM_NETWORK_WORKER_STACK_SIZE (1024*2) + +/** + * @brief ECOM-NETWORK worker stack size must be calibrated, unless using a custom worker defined in another module. + */ +#if !defined(ECOM_NETWORK_CUSTOM_WORKER) && !defined(ECOM_NETWORK_WORKER_STACK_SIZE) +#error "ECOM_NETWORK_WORKER_STACK_SIZE not declared. Please uncomment the line above to enable macro declaration and put the right value according to the stack size calibration done for your environment" +#endif // ECOM_NETWORK_WORKER_STACK_SIZE + +/** + * @brief Priority of the ECOM-NETWORK workers. + */ +#define ECOM_NETWORK_WORKER_PRIORITY (6) + +/** + * @brief Generic error returned by native functions. + */ +#define ECOM_NETWORK_ERROR (-1) + +/** + * @brief Size of a generic network interface in bytes (255 bytes). + */ +#define NETIF_NAME_SIZE (255) + +/** + * @brief Size of an IP address in bytes (16 bytes). + */ +#define IP_ADDR_SIZE (16) + +/** + * @brief Set this define to print debug traces. + */ +//#define LLECOM_NETWORK_DEBUG + +#ifdef __cplusplus + } +#endif + +#endif // ECOM_NETWORK_CONFIGURATION_H diff --git a/bsp/projects/microej/ecom-network/inc/ecom_network_helper.h b/bsp/projects/microej/ecom-network/inc/ecom_network_helper.h new file mode 100644 index 0000000..37bbb92 --- /dev/null +++ b/bsp/projects/microej/ecom-network/inc/ecom_network_helper.h @@ -0,0 +1,296 @@ +/* + * C + * + * Copyright 2020-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef ECOM_NETWORK_HELPER_H +#define ECOM_NETWORK_HELPER_H + +/** + * @file + * @brief ECOM-NETWORK helper implementation. + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 13 February 2023 + */ + +#include "ecom_network_configuration.h" +#include "microej_async_worker.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* + * IMPORTANT NOTICES + * + * This file lists the data structures used by all the LLECOM_NETWORK_* functions. + * If you add a new function and its corresponding data structure, do not forget to add + * the data structure to the ECOM_NETWORK_worker_param_t union. + * + * Some structures duplicate the definition of fields specified in generic structures instead of + * referencing the generic structures (e.g. the path and result fields). + * This decision has been made to simplify usage and readability at the expense of maintainability. + * Be careful when modifying the fields of the structures or when defining new structures. + * See the comment of each structure to identify the ones that are affected by these constraints. + */ + +/** + * @brief Data structure for enable/disable and start/stop operations. + * + * This structure is used by LLECOM_NETWORK_IMPL_enable, LLECOM_NETWORK_IMPL_disable, + * LLECOM_NETWORK_IMPL_isEnabled, LLECOM_NETWORK_IMPL_start, + * LLECOM_NETWORK_IMPL_stop, LLECOM_NETWORK_IMPL_isStarted, + * LLECOM_NETWORK_IMPL_getDNSCount, LLECOM_NETWORK_IMPL_isDNSStatic, + * LLECOM_NETWORK_IMPL_isStatic, LLECOM_NETWORK_IMPL_startConfiguration, + * LLECOM_NETWORK_IMPL_endConfiguration and LLECOM_NETWORK_IMPL_setDefault. + * + * Fields defined in this structure correspond to the parameters of these functions and + * result field corresponds to the value returned by them. + */ +typedef struct { + int8_t* netifName; /*!< [IN] The buffer that store the interface name. */ + int32_t netifNameOffset; /*!< [IN] The offset where the interface name is stored. */ + int32_t netifNameLength; /*!< [IN] The interface name buffer length. */ + int8_t getResult; /*!< [IN] false to post the request, true to get the result */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ + uint8_t netifBuffer[NETIF_NAME_SIZE]; /*!< Internal buffer. Content must not be modified. */ +} ECOM_NETWORK_netif_context_t; + +/** + * @brief Data structure for set/get DNS operations. + * + * This structure is used by LLECOM_NETWORK_IMPL_setDNS + * and LLECOM_NETWORK_IMPL_getDNS. + * + * Fields defined in this structure correspond to the parameters of these functions and + * result field corresponds to the value returned by them. + */ +typedef struct { + int8_t* netifName; /*!< [IN] The buffer that store the interface name. */ + int32_t netifNameOffset; /*!< [IN] The offset where the interface name is stored. */ + int32_t netifNameLength; /*!< [IN] The interface name buffer length. */ + int8_t* address; /*!< [IN/OUT] The buffer that store IP address to be set (input) or the buffer where the address will be get (output). */ + int32_t addressOffset; /*!< [IN/OUT] The offset where the IP address to be set is stored (input) or the offset where the address will be get (output). */ + int32_t addressLength; /*!< [IN/OUT] The IP address buffer length (input) or the address buffer length (output). */ + int32_t index; /*!< [IN/OUT] The index of the DNS (input) or the index of the DNS server (from 0 to {@link #getDNSCount()} -1) (output). */ + int8_t getResult; /*!< [IN] false to post the request, true to get the result */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ + uint8_t netifBuffer[NETIF_NAME_SIZE]; /*!< Internal buffer. Content must not be modified. */ + uint8_t addrBuffer[IP_ADDR_SIZE]; /*!< Internal buffer. Content must not be modified. */ +} ECOM_NETWORK_dns_context_t; + +/** + * @brief Data structure for get Gateway or Netmask operations. + * + * This structure is used by LLECOM_NETWORK_IMPL_getGateway, + * LLECOM_NETWORK_IMPL_setGateway, LLECOM_NETWORK_IMPL_setIP, + * LLECOM_NETWORK_IMPL_getNetmask and LLECOM_NETWORK_IMPL_setNetmask. + * + * Fields defined in this structure correspond to the parameters of these functions and + * result field corresponds to the value returned by them. + */ +typedef struct { + int8_t* netifName; /*!< [IN] The buffer that store the interface name. */ + int32_t netifNameOffset; /*!< [IN] The offset where the interface name is stored. */ + int32_t netifNameLength; /*!< [IN] The interface name buffer length. */ + int8_t* address; /*!< [IN/OUT] The buffer that store IP address to be set (input) or the buffer where the address will be get (output). */ + int32_t addressOffset; /*!< [IN/OUT] The offset where the IP address to be set is stored (input) or the offset where the address will be get (output). */ + int32_t addressLength; /*!< [IN/OUT] The IP address buffer length (input) or the address buffer length (output). */ + int8_t getResult; /*!< [IN] false to post the request, true to get the result */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ + uint8_t netifBuffer[NETIF_NAME_SIZE]; /*!< Internal buffer. Content must not be modified. */ + uint8_t addrBuffer[IP_ADDR_SIZE]; /*!< Internal buffer. Content must not be modified. */ +} ECOM_NETWORK_ip_context_t; + +/** + * @brief Data structure for use DHCP and static DNS operations. + * + * This structure is used by LLECOM_NETWORK_IMPL_useDHCP + * and LLECOM_NETWORK_IMPL_useStaticDNS. + * + * Fields defined in this structure correspond to the parameters of these functions and + * result field corresponds to the value returned by them. + */ +typedef struct { + int8_t* netifName; /*!< [IN] The buffer that store the interface name. */ + int32_t netifNameOffset; /*!< [IN] The offset where the interface name is stored. */ + int32_t netifNameLength; /*!< [IN] The interface name buffer length. */ + int8_t use; /*!< [IN] True to use DHCP / static DNS, false otherwise. */ + int8_t getResult; /*!< [IN] false to post the request, true to get the result */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ + uint8_t netifBuffer[NETIF_NAME_SIZE]; /*!< Internal buffer. Content must not be modified. */ +} ECOM_NETWORK_ip_config_t; + +/** + * @union ECOM_NETWORK_worker_param_t + */ +typedef union { + ECOM_NETWORK_netif_context_t start_context; + ECOM_NETWORK_dns_context_t set_get_DNS; + ECOM_NETWORK_ip_context_t ip_context; + ECOM_NETWORK_ip_config_t use_dhcp_dns; +} ECOM_NETWORK_worker_param_t; + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_enable and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_enable_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_disable and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_disable_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_isEnabled and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_isEnabled_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_start and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_start_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_stop and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_stop_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_isStarted and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_isStarted_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_getDNSCount and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_getDNSCount_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_getDNS and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_getDNS_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_getGateway and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_getGateway_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_getNetmask and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_getNetmask_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_isDNSStatic and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_isDNSStatic_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_isStatic and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_isStatic_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_startConfiguration and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_startConfiguration_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_endConfiguration and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_endConfiguration_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_setDNS and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_setDNS_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_setGateway and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_setGateway_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_setIP and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_setIP_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_setNetmask and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_setNetmask_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_useDHCP and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_useDHCP_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_useStaticDNS and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_useStaticDNS_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLECOM_NETWORK_IMPL_setDefault and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLECOM_NETWORK_IMPL_setDefault_action(MICROEJ_ASYNC_WORKER_job_t* job); + +#ifdef __cplusplus + } +#endif + +#endif /* ECOM_NETWORK_HELPER_H */ diff --git a/bsp/projects/microej/ecom-network/microej_ecom-network.cmake b/bsp/projects/microej/ecom-network/microej_ecom-network.cmake new file mode 100644 index 0000000..2e18fa3 --- /dev/null +++ b/bsp/projects/microej/ecom-network/microej_ecom-network.cmake @@ -0,0 +1,11 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: BSD-3-Clause + +include_guard() +message("microej/ecom-network component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/LLECOM_NETWORK_impl.c +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) \ No newline at end of file diff --git a/bsp/projects/microej/ecom-network/src/LLECOM_NETWORK_impl.c b/bsp/projects/microej/ecom-network/src/LLECOM_NETWORK_impl.c new file mode 100644 index 0000000..bad44fa --- /dev/null +++ b/bsp/projects/microej/ecom-network/src/LLECOM_NETWORK_impl.c @@ -0,0 +1,582 @@ +/* + * C + * + * Copyright 2020-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLECOM_NETWORK implementation with async worker. + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 13 February 2023 + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include +#include "sni.h" +#include "LLECOM_NETWORK_impl.h" +#include "ecom_network_configuration.h" +#include "ecom_network_helper.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * Sanity check between the expected version of the configuration and the actual version of + * the configuration. + * If an error is raised here, it means that a new version of the CCO has been installed and + * the configuration ecom_network_configuration.h must be updated based on the one provided + * by the new CCO version. + */ +#if ECOM_NETWORK_CONFIGURATION_VERSION != 2 + + #error "Version of the configuration file ecom_network_configuration.h is not compatible with this implementation." + +#endif + +#ifndef ECOM_NETWORK_CUSTOM_WORKER +/* Async worker task declaration ---------------------------------------------*/ +MICROEJ_ASYNC_WORKER_worker_declare(ecom_network_worker, ECOM_NETWORK_WORKER_JOB_COUNT, ECOM_NETWORK_worker_param_t, ECOM_NETWORK_WAITING_LIST_SIZE); +OSAL_task_stack_declare(ecom_network_worker_stack, ECOM_NETWORK_WORKER_STACK_SIZE); +#endif + +static int32_t LLECOM_NETWORK_async_exec_netif_context(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done); +static int32_t LLECOM_NETWORK_async_exec_netif_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult); +static int32_t LLECOM_NETWORK_async_exec_dns_context(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int32_t index, int8_t getResult, bool exec_write, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done); +static int32_t LLECOM_NETWORK_async_exec_get_dns_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int32_t index, int8_t getResult); +static int32_t LLECOM_NETWORK_async_exec_set_dns_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int32_t index, int8_t getResult); +static int32_t LLECOM_NETWORK_async_exec_ip_context(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult, bool exec_write, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done); +static int32_t LLECOM_NETWORK_async_exec_get_ip_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult); +static int32_t LLECOM_NETWORK_async_exec_set_ip_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult); +static int32_t LLECOM_NETWORK_async_exec_ip_config(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t use, int8_t getResult, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done); +static int32_t LLECOM_NETWORK_async_exec_ip_config_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t use, int8_t getResult); + +void LLECOM_NETWORK_initialize(void) { +#ifndef ECOM_NETWORK_CUSTOM_WORKER + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_initialize(&ecom_network_worker, (uint8_t*)"MicroEJ ECOM-NETWORK", ecom_network_worker_stack, ECOM_NETWORK_WORKER_PRIORITY); + if (status == MICROEJ_ASYNC_WORKER_INVALID_ARGS) { + SNI_throwNativeException(status, "Invalid argument for ECOM-NETWORK async worker"); + } else if (status == MICROEJ_ASYNC_WORKER_ERROR) { + SNI_throwNativeException(status, "Error while initializing ECOM-NETWORK async worker"); + } +#endif + + llecom_network_init(); +} + +int32_t LLECOM_NETWORK_IMPL_enable(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_enable, LLECOM_NETWORK_IMPL_enable_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_disable(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_disable, LLECOM_NETWORK_IMPL_disable_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_isEnabled(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_isEnabled, LLECOM_NETWORK_IMPL_isEnabled_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_start(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_start, LLECOM_NETWORK_IMPL_start_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_stop(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_stop, LLECOM_NETWORK_IMPL_stop_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_isStarted(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_isStarted, LLECOM_NETWORK_IMPL_isStarted_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_getDNSCount(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_getDNSCount, LLECOM_NETWORK_IMPL_getDNSCount_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_getDNS(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int32_t index, int8_t getResult) { + return LLECOM_NETWORK_async_exec_dns_context(netifName, netifNameOffset, netifNameLength, address, addressOffset, addressLength, index, getResult, false, (SNI_callback)LLECOM_NETWORK_IMPL_getDNS, LLECOM_NETWORK_IMPL_getDNS_action, (SNI_callback)LLECOM_NETWORK_async_exec_get_dns_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_getGateway(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_ip_context(netifName, netifNameOffset, netifNameLength, address, addressOffset, addressLength, getResult, false, (SNI_callback)LLECOM_NETWORK_IMPL_getGateway, LLECOM_NETWORK_IMPL_getGateway_action, (SNI_callback)LLECOM_NETWORK_async_exec_get_ip_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_getNetmask(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_ip_context(netifName, netifNameOffset, netifNameLength, address, addressOffset, addressLength, getResult, false, (SNI_callback)LLECOM_NETWORK_IMPL_getNetmask, LLECOM_NETWORK_IMPL_getNetmask_action, (SNI_callback)LLECOM_NETWORK_async_exec_get_ip_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_isDNSStatic(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_isDNSStatic, LLECOM_NETWORK_IMPL_isDNSStatic_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_isStatic(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_isStatic, LLECOM_NETWORK_IMPL_isStatic_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_endConfiguration(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_endConfiguration, LLECOM_NETWORK_IMPL_endConfiguration_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_startConfiguration(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_startConfiguration, LLECOM_NETWORK_IMPL_startConfiguration_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_setDNS(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int32_t index, int8_t getResult) { + return LLECOM_NETWORK_async_exec_dns_context(netifName, netifNameOffset, netifNameLength, address, addressOffset, addressLength, index, getResult, true, (SNI_callback)LLECOM_NETWORK_IMPL_setDNS, LLECOM_NETWORK_IMPL_setDNS_action, (SNI_callback)LLECOM_NETWORK_async_exec_set_dns_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_setGateway(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_ip_context(netifName, netifNameOffset, netifNameLength, address, addressOffset, addressLength, getResult, true, (SNI_callback)LLECOM_NETWORK_IMPL_setGateway, LLECOM_NETWORK_IMPL_setGateway_action, (SNI_callback)LLECOM_NETWORK_async_exec_set_ip_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_setIP(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_ip_context(netifName, netifNameOffset, netifNameLength, address, addressOffset, addressLength, getResult, true, (SNI_callback)LLECOM_NETWORK_IMPL_setIP, LLECOM_NETWORK_IMPL_setIP_action, (SNI_callback)LLECOM_NETWORK_async_exec_set_ip_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_setNetmask(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_ip_context(netifName, netifNameOffset, netifNameLength, address, addressOffset, addressLength, getResult, true, (SNI_callback)LLECOM_NETWORK_IMPL_setNetmask, LLECOM_NETWORK_IMPL_setNetmask_action, (SNI_callback)LLECOM_NETWORK_async_exec_set_ip_context_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_useDHCP(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t use, int8_t getResult) { + return LLECOM_NETWORK_async_exec_ip_config(netifName, netifNameOffset, netifNameLength, use, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_useDHCP, LLECOM_NETWORK_IMPL_useDHCP_action, (SNI_callback)LLECOM_NETWORK_async_exec_ip_config_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_useStaticDNS(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t use, int8_t getResult) { + return LLECOM_NETWORK_async_exec_ip_config(netifName, netifNameOffset, netifNameLength, use, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_useStaticDNS, LLECOM_NETWORK_IMPL_useStaticDNS_action, (SNI_callback)LLECOM_NETWORK_async_exec_ip_config_on_done); +} + +int32_t LLECOM_NETWORK_IMPL_setDefault(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + return LLECOM_NETWORK_async_exec_netif_context(netifName, netifNameOffset, netifNameLength, getResult, (SNI_callback)LLECOM_NETWORK_IMPL_setDefault, LLECOM_NETWORK_IMPL_setDefault_action, (SNI_callback)LLECOM_NETWORK_async_exec_netif_context_on_done); +} + +/** + * @brief Prepare and send an execution job to async_worker, called either from + * LLECOM_NETWORK_IMPL_enable, LLECOM_NETWORK_IMPL_disable, + * LLECOM_NETWORK_IMPL_isEnabled, LLECOM_NETWORK_IMPL_start, + * LLECOM_NETWORK_IMPL_stop, LLECOM_NETWORK_IMPL_isStarted, + * LLECOM_NETWORK_IMPL_getDNSCount, LLECOM_NETWORK_IMPL_isDNSStatic, + * LLECOM_NETWORK_IMPL_isStatic, LLECOM_NETWORK_IMPL_endConfiguration, + * LLECOM_NETWORK_IMPL_startConfiguration or LLECOM_NETWORK_IMPL_setDefault. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[in] getResult false to post the request, true to get the result + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * @param[in] action the function to execute asynchronously. + * @param[in] on_done the SNI_callback called when the job is done. + * + * @return SNI_IGNORED_RETURNED_VALUE on success, else a negative error code. + */ +static int32_t LLECOM_NETWORK_async_exec_netif_context(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&ecom_network_worker, retry_function); + if (job == NULL) { + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return ECOM_NETWORK_ERROR; + } + + ECOM_NETWORK_netif_context_t* params = (ECOM_NETWORK_netif_context_t*)job->params; + + params->netifNameOffset = netifNameOffset; + params->netifNameLength = netifNameLength; + params->getResult = getResult; + + int32_t result = SNI_retrieveArrayElements(netifName, netifNameOffset, netifNameLength, (int8_t*)¶ms->netifBuffer, + sizeof(params->netifBuffer), (int8_t**)¶ms->netifName, (uint32_t*)¶ms->netifNameLength, true); + if (result != SNI_OK) { + SNI_throwNativeIOException(result, "SNI_retrieveArrayElements: Internal error"); + } else { + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&ecom_network_worker, job, action, on_done); + if (status == MICROEJ_ASYNC_WORKER_OK) { + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + return ECOM_NETWORK_ERROR; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by + * LLECOM_NETWORK_IMPL_enable, LLECOM_NETWORK_IMPL_disable, + * LLECOM_NETWORK_IMPL_isEnabled, LLECOM_NETWORK_IMPL_start, + * LLECOM_NETWORK_IMPL_stop, LLECOM_NETWORK_IMPL_isStarted, + * LLECOM_NETWORK_IMPL_getDNSCount, LLECOM_NETWORK_IMPL_isDNSStatic, + * LLECOM_NETWORK_IMPL_isStatic, LLECOM_NETWORK_IMPL_endConfiguration, + * LLECOM_NETWORK_IMPL_startConfiguration or LLECOM_NETWORK_IMPL_setDefault is done. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[in] getResult unused parameter. + * + * @return LLECOM_NETWORK_IMPL_enable_action, LLECOM_NETWORK_IMPL_disable_action, + * LLECOM_NETWORK_IMPL_isEnabled_action, LLECOM_NETWORK_IMPL_start_action, + * LLECOM_NETWORK_IMPL_stop_action, LLECOM_NETWORK_IMPL_isStarted_action, + * LLECOM_NETWORK_IMPL_getDNSCount_action, LLECOM_NETWORK_IMPL_isDNSStatic_action, + * LLECOM_NETWORK_IMPL_isStatic_action, LLECOM_NETWORK_IMPL_endConfiguration_action or + * LLECOM_NETWORK_IMPL_startConfiguration_action function return code. + */ +static int32_t LLECOM_NETWORK_async_exec_netif_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t getResult) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + ECOM_NETWORK_netif_context_t* params = (ECOM_NETWORK_netif_context_t*)job->params; + + (void)netifName; + (void)netifNameOffset; + (void)netifNameLength; + (void)getResult; + + int32_t result = params->result; + + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + + return result; +} + +/** + * @brief Prepare and send an execution job to async_worker, called either from + * LLECOM_NETWORK_IMPL_getDNS or LLECOM_NETWORK_IMPL_setDNS. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[in/out] address the buffer where the address will be / is stored + * @param[in] addressOffset the offset where the address will be stored + * @param[in] addressLength the address buffer length + * @param[in] index the index of the DNS server (from 0 to {@link #getDNSCount()} -1) + * @param[in] getResult false to post the request, true to get the result + * @param[in] exec_write true if the address buffer content need to be sent to the async_worker job, else false. + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * @param[in] action the function to execute asynchronously. + * @param[in] on_done the SNI_callback called when the job is done. + * + * @return SNI_IGNORED_RETURNED_VALUE on success, else a negative error code. + */ +static int32_t LLECOM_NETWORK_async_exec_dns_context(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int32_t index, int8_t getResult, bool exec_write, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&ecom_network_worker, retry_function); + if (job == NULL) { + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return ECOM_NETWORK_ERROR; + } + + ECOM_NETWORK_dns_context_t* params = (ECOM_NETWORK_dns_context_t*)job->params; + + params->netifNameOffset = netifNameOffset; + params->netifNameLength = netifNameLength; + params->addressOffset = addressOffset; + params->addressLength = addressLength; + params->index = index; + params->getResult = getResult; + + bool do_copy = exec_write; + int32_t result = 0; + result = SNI_retrieveArrayElements(netifName, netifNameOffset, netifNameLength, (int8_t*)¶ms->netifBuffer, + sizeof(params->netifBuffer), (int8_t**)¶ms->netifName, (uint32_t*)¶ms->netifNameLength, true); + result |= SNI_retrieveArrayElements(address, addressOffset, addressLength, (int8_t*)¶ms->addrBuffer, + sizeof(params->addrBuffer), (int8_t**)¶ms->address, (uint32_t*)¶ms->addressLength, do_copy); + if (result != SNI_OK) { + SNI_throwNativeIOException(result, "SNI_retrieveArrayElements: Internal error"); + } else { + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&ecom_network_worker, job, action, on_done); + if (status == MICROEJ_ASYNC_WORKER_OK) { + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + return ECOM_NETWORK_ERROR; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by + * LLECOM_NETWORK_IMPL_getDNS is done. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[out] address the buffer where the address will be stored + * @param[in] addressOffset the offset where the address will be stored + * @param[in] addressLength the address buffer length + * @param[in] index the index of the DNS server (from 0 to {@link #getDNSCount()} -1) + * @param[in] getResult unused parameter. + * + * @return LLECOM_NETWORK_IMPL_getDNS_action function return code. + */ +static int32_t LLECOM_NETWORK_async_exec_get_dns_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int32_t index, int8_t getResult) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + ECOM_NETWORK_dns_context_t* params = (ECOM_NETWORK_dns_context_t*)job->params; + + (void)netifName; + (void)netifNameOffset; + (void)netifNameLength; + (void)index; + (void)getResult; + + int32_t result = params->result; + if (result >= 0) { + int32_t release_result = SNI_flushArrayElements(address, addressOffset, addressLength, (int8_t*)(params->address + params->addressOffset), params->addressLength); + if (release_result != SNI_OK) { + SNI_throwNativeIOException(release_result, "SNI_flushArrayElements: Internal error"); + } + } + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by + * LLECOM_NETWORK_IMPL_setDNS is done. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[in] address the buffer where the address is stored + * @param[in] addressOffset the offset where the address will be stored + * @param[in] addressLength the address buffer length + * @param[in] index the index of the DNS server (from 0 to {@link #getDNSCount()} -1) + * @param[in] getResult unused parameter. + * + * @return LLECOM_NETWORK_IMPL_setDNS_action function return code. + */ +static int32_t LLECOM_NETWORK_async_exec_set_dns_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int32_t index, int8_t getResult) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + ECOM_NETWORK_dns_context_t* params = (ECOM_NETWORK_dns_context_t*)job->params; + + (void)netifName; + (void)netifNameOffset; + (void)netifNameLength; + (void)address; + (void)addressOffset; + (void)addressLength; + (void)index; + (void)getResult; + + int32_t result = params->result; + + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + + return result; +} + +/** + * @brief Prepare and send an execution job to async_worker, called either from + * LLECOM_NETWORK_IMPL_getGateway, LLECOM_NETWORK_IMPL_getNetmask, + * LLECOM_NETWORK_IMPL_setGateway, LLECOM_NETWORK_IMPL_setIP or + * LLECOM_NETWORK_IMPL_setNetmask. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[in/out] address the buffer where the address will be / is stored + * @param[in] addressOffset the offset where the address will be stored + * @param[in] addressLength the address buffer length + * @param[in] getResult false to post the request, true to get the result + * @param[in] exec_write true if the address buffer content need to be sent to the async_worker job, else false. + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * @param[in] action the function to execute asynchronously. + * @param[in] on_done the SNI_callback called when the job is done. + * + * @return SNI_IGNORED_RETURNED_VALUE on success, else a negative error code. + */ +static int32_t LLECOM_NETWORK_async_exec_ip_context(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult, bool exec_write, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&ecom_network_worker, retry_function); + if (job == NULL) { + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return ECOM_NETWORK_ERROR; + } + + ECOM_NETWORK_ip_context_t* params = (ECOM_NETWORK_ip_context_t*)job->params; + + params->netifNameOffset = netifNameOffset; + params->netifNameLength = netifNameLength; + params->addressOffset = addressOffset; + params->addressLength = addressLength; + params->getResult = getResult; + + bool do_copy = exec_write; + int32_t result = 0; + result = SNI_retrieveArrayElements(netifName, netifNameOffset, netifNameLength, (int8_t*)¶ms->netifBuffer, + sizeof(params->netifBuffer), (int8_t**)¶ms->netifName, (uint32_t*)¶ms->netifNameLength, true); + result |= SNI_retrieveArrayElements(address, addressOffset, addressLength, (int8_t*)¶ms->addrBuffer, + sizeof(params->addrBuffer), (int8_t**)¶ms->address, (uint32_t*)¶ms->addressLength, do_copy); + if (result != SNI_OK) { + SNI_throwNativeIOException(result, "SNI_retrieveArrayElements: Internal error"); + } else { + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&ecom_network_worker, job, action, on_done); + if (status == MICROEJ_ASYNC_WORKER_OK) { + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + return ECOM_NETWORK_ERROR; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by + * LLECOM_NETWORK_IMPL_getGateway or LLECOM_NETWORK_IMPL_getNetmask is done. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[out] address the buffer where the address will be stored + * @param[in] addressOffset the offset where the address will be stored + * @param[in] addressLength the address buffer length + * @param[in] getResult unused parameter. + * + * @return LLECOM_NETWORK_IMPL_getGateway_action or LLECOM_NETWORK_IMPL_getNetmask_action function return code. + */ +static int32_t LLECOM_NETWORK_async_exec_get_ip_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + ECOM_NETWORK_ip_context_t* params = (ECOM_NETWORK_ip_context_t*)job->params; + + (void)netifName; + (void)netifNameOffset; + (void)netifNameLength; + (void)getResult; + + int32_t result = params->result; + if (result >= 0) { + int32_t release_result = SNI_flushArrayElements(address, addressOffset, addressLength, (int8_t*)(params->address + params->addressOffset), params->addressLength); + if (release_result != SNI_OK) { + SNI_throwNativeIOException(release_result, "SNI_flushArrayElements: Internal error"); + } + } + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by + * LLECOM_NETWORK_IMPL_setGateway, LLECOM_NETWORK_IMPL_setIP or + * LLECOM_NETWORK_IMPL_setNetmask is done. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[in] address the buffer where the address is stored + * @param[in] addressOffset the offset where the address will be stored + * @param[in] addressLength the address buffer length + * @param[in] getResult unused parameter. + * + * @return LLECOM_NETWORK_IMPL_setGateway_action, + * LLECOM_NETWORK_IMPL_setIP_action or LLECOM_NETWORK_IMPL_setNetmask_action function return code. + */ +static int32_t LLECOM_NETWORK_async_exec_set_ip_context_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t* address, int32_t addressOffset, int32_t addressLength, int8_t getResult) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + ECOM_NETWORK_ip_context_t* params = (ECOM_NETWORK_ip_context_t*)job->params; + + (void)netifName; + (void)netifNameOffset; + (void)netifNameLength; + (void)address; + (void)addressOffset; + (void)addressLength; + (void)getResult; + + int32_t result = params->result; + + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + + return result; +} + +/** + * @brief Prepare and send an execution job to async_worker, called either from + * LLECOM_NETWORK_IMPL_useDHCP or LLECOM_NETWORK_IMPL_useStaticDNS. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[in] use true to use DHCP/DNS, false otherwise + * @param[in] getResult false to post the request, true to get the result + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * @param[in] action the function to execute asynchronously. + * @param[in] on_done the SNI_callback called when the job is done. + * + * @return SNI_IGNORED_RETURNED_VALUE on success, else a negative error code. + */ +static int32_t LLECOM_NETWORK_async_exec_ip_config(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t use, int8_t getResult, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&ecom_network_worker, retry_function); + if (job == NULL) { + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return ECOM_NETWORK_ERROR; + } + + ECOM_NETWORK_ip_config_t* params = (ECOM_NETWORK_ip_config_t*)job->params; + + params->netifNameOffset = netifNameOffset; + params->netifNameLength = netifNameLength; + params->use = use; + params->getResult = getResult; + + int32_t result = SNI_retrieveArrayElements(netifName, netifNameOffset, netifNameLength, (int8_t*)¶ms->netifBuffer, + sizeof(params->netifBuffer), (int8_t**)¶ms->netifName, (uint32_t*)¶ms->netifNameLength, true); + if (result != SNI_OK) { + SNI_throwNativeIOException(result, "SNI_retrieveArrayElements: Internal error"); + } else { + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&ecom_network_worker, job, action, on_done); + if (status == MICROEJ_ASYNC_WORKER_OK) { + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + return ECOM_NETWORK_ERROR; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by + * LLECOM_NETWORK_IMPL_useDHCP or LLECOM_NETWORK_IMPL_useStaticDNS is done. + * + * @param[in] netifName the buffer that store interface name + * @param[in] netifNameOffset the offset where the interface name is stored + * @param[in] netifNameLength the interface name buffer length + * @param[in] use true to use DHCP/DNS, false otherwise + * @param[in] getResult unused parameter. + * + * @return LLECOM_NETWORK_IMPL_useDHCP_action or + * LLECOM_NETWORK_IMPL_useStaticDNS_action function return code. + */ +static int32_t LLECOM_NETWORK_async_exec_ip_config_on_done(int8_t* netifName, int32_t netifNameOffset, int32_t netifNameLength, int8_t use, int8_t getResult) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + ECOM_NETWORK_ip_config_t* params = (ECOM_NETWORK_ip_config_t*)job->params; + + (void)netifName; + (void)netifNameOffset; + (void)netifNameLength; + (void)use; + (void)getResult; + + int32_t result = params->result; + + MICROEJ_ASYNC_WORKER_free_job(&ecom_network_worker, job); + + return result; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/flash_config/flash_config.c b/bsp/projects/microej/flash_config/flash_config.c new file mode 100644 index 0000000..91278c5 --- /dev/null +++ b/bsp/projects/microej/flash_config/flash_config.c @@ -0,0 +1,76 @@ +/* + * Copyright 2021-2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "flash_config.h" + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.flash_config" +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ +#if defined(BOOT_HEADER_ENABLE) && (BOOT_HEADER_ENABLE == 1) +#if defined(__ARMCC_VERSION) || defined(__GNUC__) +__attribute__((section(".flash_conf"), used)) +#elif defined(__ICCARM__) +#pragma location = ".flash_conf" +#endif +const flexspi_nor_config_t flexspi_config = { + .memConfig = + { + .tag = FLASH_CONFIG_BLOCK_TAG, + .version = FLASH_CONFIG_BLOCK_VERSION, + .csHoldTime = 3, + .csSetupTime = 3, + .deviceModeCfgEnable = 1, + .deviceModeSeq = {.seqNum = 1, .seqId = 2}, + .deviceModeArg = 0x40, + .configCmdEnable = 0, + .deviceType = 0x1, + .sflashPadType = kSerialFlash_4Pads, + .serialClkFreq = 7, + .sflashA1Size = 0x4000000U, + .sflashA2Size = 0, + .sflashB1Size = 0, + .sflashB2Size = 0, + .lookupTable = + { + /* Read */ + [0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), + [1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), + + /* Read Status */ + [4 * 1 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x04), + + /* Write Status */ + [4 * 2 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x01), + + /* Write Enable */ + [4 * 3 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP_EXE, FLEXSPI_1PAD, 0x00), + + /* Sector erase */ + [4 * 5 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x20, RADDR_SDR, FLEXSPI_1PAD, 0x18), + + /* Block erase */ + [4 * 8 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x52, RADDR_SDR, FLEXSPI_1PAD, 0x18), + + /* Page program */ + [4 * 9 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x02, RADDR_SDR, FLEXSPI_1PAD, 0x18), + [4 * 9 + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x00, STOP_EXE, FLEXSPI_1PAD, 0x00), + + /* chip erase */ + [4 * 11 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x60, STOP_EXE, FLEXSPI_1PAD, 0x00), + }, + }, + .pageSize = 0x100, + .sectorSize = 0x1000, + .ipcmdSerialClkFreq = 0, + .blockSize = 0x8000, + .fcb_fill[0] = 0xFFFFFFFF, +}; +#endif /* BOOT_HEADER_ENABLE */ diff --git a/bsp/projects/microej/flash_config/flash_config.h b/bsp/projects/microej/flash_config/flash_config.h new file mode 100644 index 0000000..2027d65 --- /dev/null +++ b/bsp/projects/microej/flash_config/flash_config.h @@ -0,0 +1,218 @@ +/* + * Copyright 2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __FLASH_CONFIG__ +#define __FLASH_CONFIG__ + +#include +#include +#include "fsl_common.h" + +/*! @name Driver version */ +/*@{*/ +/*! @brief FLASH_CONFIG driver version 2.0.0. */ +#define FSL_FLASH_CONFIG_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) +/*@}*/ + +/******************************************************************************* + * Definition + ******************************************************************************/ + +/* FLEXSPI memory config block related defintions */ +#define FLASH_CONFIG_BLOCK_TAG (0x42464346) +#define FLASH_CONFIG_BLOCK_VERSION (0x00000000) + +#define CMD_SDR 0x01 +#define CMD_DDR 0x21 +#define RADDR_SDR 0x02 +#define RADDR_DDR 0x22 +#define CADDR_SDR 0x03 +#define CADDR_DDR 0x23 +#define MODE1_SDR 0x04 +#define MODE1_DDR 0x24 +#define MODE2_SDR 0x05 +#define MODE2_DDR 0x25 +#define MODE4_SDR 0x06 +#define MODE4_DDR 0x26 +#define MODE8_SDR 0x07 +#define MODE8_DDR 0x27 +#define WRITE_SDR 0x08 +#define WRITE_DDR 0x28 +#define READ_SDR 0x09 +#define READ_DDR 0x29 +#define LEARN_SDR 0x0A +#define LEARN_DDR 0x2A +#define DATSZ_SDR 0x0B +#define DATSZ_DDR 0x2B +#define DUMMY_SDR 0x0C +#define DUMMY_DDR 0x2C +#define DUMMY_RWDS_SDR 0x0D +#define DUMMY_RWDS_DDR 0x2D +#define JMP_ON_CS 0x1F +#define STOP_EXE 0 + +#define FLEXSPI_1PAD 0 +#define FLEXSPI_2PAD 1 +#define FLEXSPI_4PAD 2 +#define FLEXSPI_8PAD 3 + +#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ + FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + +/* !@brief Data pad used in Read command */ +enum +{ + kSerialFlash_1Pads = 1, + kSerialFlash_2Pads = 2, + kSerialFlash_4Pads = 4, + kSerialFlash_8Pads = 8, +}; + +/* !@brief FLEXSPI clock configuration - In High speed boot mode mode */ +enum +{ + kFlexSpiSerialClk_30MHz = 1, + kFlexSpiSerialClk_50MHz = 2, + kFlexSpiSerialClk_60MHz = 3, + kFlexSpiSerialClk_80MHz = 4, + kFlexSpiSerialClk_100MHz = 5, + kFlexSpiSerialClk_120MHz = 6, + kFlexSpiSerialClk_133MHz = 7, + kFlexSpiSerialClk_166MHz = 8, + kFlexSpiSerialClk_200MHz = 9, +}; + +/* !@brief FLEXSPI clock configuration - In Normal boot SDR mode */ +enum +{ + kFlexSpiSerialClk_SDR_24MHz = 1, + kFlexSpiSerialClk_SDR_48MHz = 2, +}; + +/* !@brief FLEXSPI clock configuration - In Normal boot DDR mode */ +enum +{ + kFlexSpiSerialClk_DDR_48MHz = 1, +}; + +/* !@brief Misc feature bit definitions */ +enum +{ + kFlexSpiMiscOffset_DiffClkEnable = 0, /* !< Bit for Differential clock enable */ + kFlexSpiMiscOffset_WordAddressableEnable = 3, /* !< Bit for Word Addressable enable */ + kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, /* !< Bit for Safe Configuration Frequency enable */ + kFlexSpiMiscOffset_DdrModeEnable = 6, /* !< Bit for DDR clock confiuration indication. */ +}; + +/* !@brief Flash Configuration Command Type */ +enum +{ + kDeviceConfigCmdType_Generic, /* !< Generic command, for example: configure dummy cycles, drive strength, etc */ + kDeviceConfigCmdType_QuadEnable, /* !< Quad Enable command */ + kDeviceConfigCmdType_Spi2Xpi, /* !< Switch from SPI to DPI/QPI/OPI mode */ + kDeviceConfigCmdType_Xpi2Spi, /* !< Switch from DPI/QPI/OPI to SPI mode */ + kDeviceConfigCmdType_Spi2NoCmd, /* !< Switch to 0-4-4/0-8-8 mode */ + kDeviceConfigCmdType_Reset, /* !< Reset device command */ +}; + +typedef struct +{ + uint8_t time_100ps; /* !< Data valid time, in terms of 100ps */ + uint8_t delay_cells; /* !< Data valid time, in terms of delay cells */ +} flexspi_dll_time_t; + +/* !@brief FlexSPI LUT Sequence structure */ +typedef struct _lut_sequence +{ + uint8_t seqNum; /* !< Sequence Number, valid number: 1-16 */ + uint8_t seqId; /* !< Sequence Index, valid number: 0-15 */ + uint16_t reserved; +} flexspi_lut_seq_t; + +/* !@brief FlexSPI Memory Configuration Block */ +typedef struct _FlexSPIConfig +{ + uint32_t tag; /* !< [0x000-0x003] Tag, fixed value 0x42464346UL */ + uint32_t version; /* !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix */ + uint32_t reserved0; /* !< [0x008-0x00b] Reserved for future use */ + uint8_t readSampleClkSrc; /* !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 */ + uint8_t csHoldTime; /* !< [0x00d-0x00d] CS hold time, default value: 3 */ + uint8_t csSetupTime; /* !< [0x00e-0x00e] CS setup time, default value: 3 */ + uint8_t columnAddressWidth; /* !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For + Serial NAND, need to refer to datasheet */ + uint8_t deviceModeCfgEnable; /* !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable */ + uint8_t deviceModeType; /* !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, + Generic configuration, etc. */ + uint16_t waitTimeCfgCommands; /* !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for + DPI/QPI/OPI switch or reset command */ + flexspi_lut_seq_t deviceModeSeq; /* !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - + LUt sequence number, [31:16] Reserved */ + uint32_t deviceModeArg; /* !< [0x018-0x01b] Argument/Parameter for device configuration */ + uint8_t configCmdEnable; /* !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable */ + uint8_t configModeType[3]; /* !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe */ + flexspi_lut_seq_t configCmdSeqs[3]; /* !< [0x020-0x02b] Sequence info for Device Configuration command, similar as + deviceModeSeq */ + uint32_t reserved1; /* !< [0x02c-0x02f] Reserved for future use */ + uint32_t configCmdArgs[3]; /* !< [0x030-0x03b] Arguments/Parameters for device Configuration commands */ + uint32_t reserved2; /* !< [0x03c-0x03f] Reserved for future use */ + uint32_t controllerMiscOption; /* !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for + more details */ + uint8_t deviceType; /* !< [0x044-0x044] Device Type: See Flash Type Definition for more details */ + uint8_t sflashPadType; /* !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal */ + uint8_t serialClkFreq; /* !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot + Chapter for more details */ + uint8_t lutCustomSeqEnable; /* !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot + be done using 1 LUT sequence, currently, only applicable to HyperFLASH */ + uint32_t reserved3[2]; /* !< [0x048-0x04f] Reserved for future use */ + uint32_t sflashA1Size; /* !< [0x050-0x053] Size of Flash connected to A1 */ + uint32_t sflashA2Size; /* !< [0x054-0x057] Size of Flash connected to A2 */ + uint32_t sflashB1Size; /* !< [0x058-0x05b] Size of Flash connected to B1 */ + uint32_t sflashB2Size; /* !< [0x05c-0x05f] Size of Flash connected to B2 */ + uint32_t csPadSettingOverride; /* !< [0x060-0x063] CS pad setting override value */ + uint32_t sclkPadSettingOverride; /* !< [0x064-0x067] SCK pad setting override value */ + uint32_t dataPadSettingOverride; /* !< [0x068-0x06b] data pad setting override value */ + uint32_t dqsPadSettingOverride; /* !< [0x06c-0x06f] DQS pad setting override value */ + uint32_t timeoutInMs; /* !< [0x070-0x073] Timeout threshold for read status command */ + uint32_t commandInterval; /* !< [0x074-0x077] CS deselect interval between two commands */ + flexspi_dll_time_t dataValidTime[2]; /* !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B */ + uint16_t busyOffset; /* !< [0x07c-0x07d] Busy offset, valid value: 0-31 */ + uint16_t busyBitPolarity; /* !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - + busy flag is 0 when flash device is busy */ + uint32_t lookupTable[64]; /* !< [0x080-0x17f] Lookup table holds Flash command sequences */ + flexspi_lut_seq_t lutCustomSeq[12]; /* !< [0x180-0x1af] Customizable LUT Sequences */ + uint32_t reserved4[4]; /* !< [0x1b0-0x1bf] Reserved for future use */ +} flexspi_mem_config_t; +/* + * Serial NOR configuration block + */ +typedef struct _flexspi_nor_config +{ + flexspi_mem_config_t memConfig; /* !< Common memory configuration info via FlexSPI */ + uint32_t pageSize; /* !< Page size of Serial NOR */ + uint32_t sectorSize; /* !< Sector size of Serial NOR */ + uint8_t ipcmdSerialClkFreq; /* !< Clock frequency for IP command */ + uint8_t isUniformBlockSize; /* !< Sector/Block size is the same */ + uint8_t isDataOrderSwapped; /* !< Data order (D0, D1, D2, D3) is swapped (D1,D0, D3, D2) */ + uint8_t reserved0[1]; /* !< Reserved for future use */ + uint8_t serialNorType; /* !< Serial NOR Flash type: 0/1/2/3 */ + uint8_t needExitNoCmdMode; /* !< Need to exit NoCmd mode before other IP command */ + uint8_t halfClkForNonReadCmd; /* !< Half the Serial Clock for non-read command: true/false */ + uint8_t needRestoreNoCmdMode; /* !< Need to Restore NoCmd mode after IP commmand execution */ + uint32_t blockSize; /* !< Block size */ + uint32_t flashStateCtx; /* !< Flash State Context */ + uint32_t reserve2[10]; /* !< Reserved for future use */ + uint32_t fcb_fill[0x280]; /* !< Fill */ +} flexspi_nor_config_t; +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __FLASH_CONFIG__ */ diff --git a/bsp/projects/microej/fs/inc/fs_configuration.h b/bsp/projects/microej/fs/inc/fs_configuration.h new file mode 100644 index 0000000..dd9890f --- /dev/null +++ b/bsp/projects/microej/fs/inc/fs_configuration.h @@ -0,0 +1,129 @@ +/* + * C + * + * Copyright 2014-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef FS_CONFIGURATION_H +#define FS_CONFIGURATION_H +#include "fsl_debug_console.h" + +/** + * @file + * @brief LLFS configuration. + * @author MicroEJ Developer Team + * @version 2.1.0 + * @date 17 June 2022 + */ + +#include "microej_async_worker.h" + +#ifdef __cplusplus + extern "C" { +#endif + +//#error "This header must be customized with platform specific configuration. Remove this #error when done. This file is not modified when a new version of the CCO is installed." + +/** + * @brief Compatibility sanity check value. + * This define value is checked in the implementation to validate that the version of this configuration + * is compatible with the implementation. + * + * This value must not be changed by the user of the CCO. + * This value must be incremented by the implementor of the CCO when a configuration define is added, deleted or modified. + */ +#define FS_CONFIGURATION_VERSION (1) + +/** + * @brief Use this macro to define the initialization function of the file system stack. + * Called from LLFS_IMPL_initialize(). + * By default this macro does nothing. + */ +extern bool SDCARD_waitCardReady(); + +#define llfs_init() SDCARD_waitCardReady() + +/** + * @brief Set this define to use a custom worker to handle FS asynchronous jobs. + */ +//#define FS_CUSTOM_WORKER + +/** + * @brief Define FS custom worker if required. + */ +#ifdef FS_CUSTOM_WORKER +extern MICROEJ_ASYNC_WORKER_handle_t my_custom_worker; +#define fs_worker my_custom_worker +#else +extern MICROEJ_ASYNC_WORKER_handle_t fs_worker; +#endif + +/** + * @brief Number of workers dedicated to the FS in async_worker. + */ +#define FS_WORKER_JOB_COUNT (4) + +/** + * @brief Size of the waiting list for FS jobs in async_worker. + */ +#define FS_WAITING_LIST_SIZE (16) + +/** + * @brief Size of the FS stack in bytes. + */ +#define FS_WORKER_STACK_SIZE (1024*2) + +/** + * @brief FS worker stack size must be calibrated, unless using a custom worker defined in another module. + */ +#if !defined(FS_CUSTOM_WORKER) && !defined(FS_WORKER_STACK_SIZE) +#error "FS_WORKER_STACK_SIZE not declared. Please uncomment the line above to enable macro declaration and put the right value according to the stack size calibration done for your environment" +#endif // FS_WORKER_STACK_SIZE + +/** + * @brief Priority of the FS workers. + */ +#define FS_WORKER_PRIORITY (6) + +/** + * @brief Maximum path length. + */ +#define FS_PATH_LENGTH (256) + +/** + * @brief Size of the IO buffer in bytes. + */ +#define FS_IO_BUFFER_SIZE (2048) + +/** + * @brief Copies a file path from an input buffer to another buffer that will be sent to + * the async_worker job, checking against path size constraints. + * + * @param[in] path caller buffer where the file path is stored. + * @param[in] path_param buffer where the file path will be copied if the path size constraints are solved. + * + * @return LLFS_OK on success, else a negative error code. + */ +int32_t LLFS_set_path_param(uint8_t* path, uint8_t* path_param); + +/** + * @brief Set this define to print debug traces. + */ +//#define LLFS_DEBUG + +#ifdef LLFS_DEBUG +#include "fsl_debug_console.h" +#define LLFS_DEBUG_TRACE PRINTF("[DEBUG] ");PRINTF +#else +#define LLFS_DEBUG_TRACE(...) +//#define LLFS_DEBUG_TRACE DbgConsole_Printf +#endif + +#define FF_DIR DIR + +#ifdef __cplusplus + } +#endif + +#endif // FS_CONFIGURATION_H diff --git a/bsp/projects/microej/fs/inc/fs_helper.h b/bsp/projects/microej/fs/inc/fs_helper.h new file mode 100644 index 0000000..670a452 --- /dev/null +++ b/bsp/projects/microej/fs/inc/fs_helper.h @@ -0,0 +1,587 @@ +/* + * C + * + * Copyright 2014-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef FS_HELPER_H +#define FS_HELPER_H + +/** + * @file + * @brief LLFS helper implementation. + * @author MicroEJ Developer Team + * @version 2.1.1 + * @date 26 April 2023 + */ + +#include "fs_configuration.h" +#include "microej_async_worker.h" +#include "LLFS_impl.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* + * IMPORTANT NOTICES + * + * This file lists the data structures used by all the LLFS_* functions. + * If you add a new function and its corresponding data structure, do not forget to add + * the data structure to the FS_worker_param_t union. + * + * Some structures duplicate the definition of fields specified in generic structures instead of + * referencing the generic structures (e.g. the path and result fields). + * This decision has been made to simplify usage and readability at the expense of maintainability. + * Be careful when modifying the fields of the structures or when defining new structures. + * See the comment of each structure to identify the ones that are affected by these constraints. + */ + +/** + * @brief Data structure for path operations. + * + * This structure is used by LLFS_IMPL_create, LLFS_IMPL_set_read_only, + * LLFS_IMPL_open_directory, LLFS_IMPL_exist, + * LLFS_IMPL_make_directory, LLFS_IMPL_is_directory, + * LLFS_IMPL_is_file and LLFS_IMPL_delete. + * + * Fields defined in this structure correspond to the parameters of these functions, and + * result field corresponds to the value returned by them. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ +} FS_path_operation_t; + +/** + * @brief Data structure for path operations that return a 64-bit result. + * + * This structure is used by LLFS_IMPL_get_length. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ + int64_t result; /*!< [OUT] Result of the operation. */ +} FS_path64_operation_t; + +/** + * @brief Data structure for operations getting/setting the last modification of a file. + * + * This structure is used by LLFS_IMPL_get_last_modified() and + * LLFS_IMPL_set_last_modified(). + * + * Fields defined in this structure correspond to the parameters of these functions, and + * result field corresponds to the value returned by them. + * + * @warning path and result fields must be declared in the same way as in + * FS_path_operation_t structure. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + LLFS_date_t date; /*!< [IN/OUT] Date of the last modification. Input for the date setting, output for the date getting. */ +} FS_last_modified_t; + +/** + * @brief Data structure for creation operations. + * + * This structure is used by LLFS_IMPL_create. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + * + * @warning path and result fields must be declared in the same way as in + * FS_path_operation_t structure. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_create_t; + +/** + * @brief Data structure for renaming operations. + * + * This structure is used by LLFS_IMPL_rename_to. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + * + * @warning path and result fields must be declared in the same way as in + * FS_path_operation_t structure. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Old path of the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + uint8_t new_path[FS_PATH_LENGTH]; /*!< [IN] New path of the operation. */ +} FS_rename_to_t; + +/** + * @brief Data structure for get space operations. + * + * This structure is used by LLFS_IMPL_get_space_size. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + * + * @warning path and result fields must be declared in the same way as in + * FS_path64_operation_t structure. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ + int64_t result; /*!< [OUT] Result of the operation. */ + int32_t space_type; /*!< [IN] Type of space. */ +} FS_get_space_size; + +/** + * @brief Data structure for operations about file accessibility. + * + * This structure is used by LLFS_IMPL_is_accessible. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + * + * @warning path and result fields must be declared in the same way as in + * FS_path_operation_t structure. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t access; /*!< [IN] Type of access. */ +} FS_is_accessible_t; + +/** + * @brief Data structure for permission operations. + * + * This structure is used by LLFS_IMPL_set_permission. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + * + * @warning path and result fields must be declared in the same way as in + * FS_path_operation_t structure. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t access; /*!< [IN] Type of the new access. */ + int32_t enable; /*!< [IN] Enable/Disable switch. */ + int32_t owner; /*!< [IN] File owner. */ +} FS_set_permission_t; + +/** + * @brief Data structure for file opening operations. + * + * This structure is used by LLFS_File_IMPL_open. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + * + * @warning path and result fields must be declared in the same way as in + * FS_path_operation_t structure. + */ +typedef struct { + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + uint8_t mode; /*!< [IN] Opening mode. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_open_t; + +/** + * @brief Data structure for directory operations. + * + * This structure is used by LLFS_async_exec_directory_job. + * + * The field defined in this structure corresponds to the parameters of this function. + */ +typedef struct { + int32_t directory_ID; /*!< [IN] ID of the directory on which to perform the operation. */ +} FS_directory_operation_t; + +/** + * @brief Data structure for directory read operations. + * + * This structure is used by LLFS_IMPL_read_directory. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + * + * @warning path and result fields must be declared in the same way as in + * FS_path_operation_t structure. + */ +typedef struct { + int32_t directory_ID; /*!< [IN] ID of the directory on which to perform the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + uint8_t path[FS_PATH_LENGTH]; /*!< [IN] Path of the operation. */ +} FS_read_directory_t; + +/** + * @brief Data structure for directory close operation. + * + * This structure is used by LLFS_IMPL_close_directory. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + int32_t directory_ID; /*!< [IN] ID of the directory on which to perform the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ +} FS_close_directory_t; + +/** + * @brief Data structure for read/write operations. + * + * This structure is used by LLFS_File_IMPL_write, LLFS_File_IMPL_read, + * LLFS_File_IMPL_write_byte and LLFS_File_IMPL_read_byte. + * + * Fields defined in this structure correspond to the parameters of these functions, and + * result field corresponds to the value returned by them. + */ +typedef struct { + int32_t file_id; /*!< [IN] ID of the file on which to perform the operation. */ + uint8_t* data; /*!< [IN/OUT] Data read (output) or data to write (input). */ + int32_t length; /*!< [IN] Length of the data. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ + uint8_t buffer[FS_IO_BUFFER_SIZE]; /*!< Internal buffer. Content must not be modified. */ +} FS_write_read_t; + +/** + * @brief Data structure for file closing operations. + * + * This structure is used by LLFS_File_IMPL_close. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + int32_t file_id; /*!< [IN] ID of the file on which to perform the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_close_t; + +/** + * @brief Data structure for seek operation. + * + * This structure is used by LLFS_File_IMPL_seek. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + int32_t file_id; /*!< [IN] ID of the file on which to perform the operation. */ + int64_t n; /*!< [IN] the new position of the file pointer. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_seek_t; + +/** + * @brief Data structure for get file pointer operation. + * + * This structure is used by LLFS_File_IMPL_getfp. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + int32_t file_id; /*!< [IN] ID of the file on which to perform the operation. */ + int64_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_getfp_t; + +/** + * @brief Data structure for set length operation. + * + * This structure is used by LLFS_File_IMPL_set_length. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + int32_t file_id; /*!< [IN] ID of the file on which to perform the operation. */ + int64_t length; /*!< [IN] the new length of the file. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_set_length_t; + +/** + * @brief Data structure for get length with fd operation. + * + * This structure is used by LLFS_File_IMPL_get_length_with_fd. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + int32_t file_id; /*!< [IN] ID of the file on which to perform the operation. */ + int64_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_get_length_with_fd_t; + +/** + * @brief Data structure for availability checking operation. + * + * This structure is used by LLFS_File_IMPL_available. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + int32_t file_id; /*!< [IN] ID of the file on which to perform the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_available_t; + +/** + * @brief Data structure for file flushing operations. + * + * This structure is used by LLFS_File_IMPL_flush. + * + * Fields defined in this structure correspond to the parameters of this function, and + * result field corresponds to the value returned by it. + */ +typedef struct { + int32_t file_id; /*!< [IN] ID of the file on which to perform the operation. */ + int32_t result; /*!< [OUT] Result of the operation. */ + int32_t error_code; /*!< [OUT] Error code returned in case of error. */ + char* error_message; /*!< [OUT] Error message related to the error code. */ +} FS_flush_t; +/** + * @union FS_worker_param_t + */ +typedef union { + FS_path_operation_t path_operation; + FS_path64_operation_t path64_operation; + FS_last_modified_t get_last_modified; + FS_create_t create; + FS_rename_to_t rename_to; + FS_directory_operation_t directory_operation; + FS_read_directory_t read_directory; + FS_close_directory_t close_directory; + FS_last_modified_t set_last_modified; + FS_is_accessible_t is_accessible; + FS_set_permission_t set_permission; + FS_open_t open; + FS_write_read_t write; + FS_close_t close; + FS_seek_t seek; + FS_getfp_t getfp; + FS_set_length_t set_length; + FS_get_length_with_fd_t get_length_with_fd; + FS_available_t available; + FS_flush_t flush; +} FS_worker_param_t; + +/** + * @brief Action requested by LLFS_IMPL_get_last_modified and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_get_last_modified_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_set_read_only and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_set_read_only_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_create and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_create_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_open_directory and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_open_directory_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_read_directory and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_read_directory_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_close_directory and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_close_directory_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_rename_to and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_rename_to_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_get_length and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_get_length_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_exist and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_exist_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_get_space_size and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_get_space_size_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_make_directory and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_make_directory_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_is_hidden and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_is_hidden_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_is_directory and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_is_directory_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_is_file and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_is_file_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_set_last_modified and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_set_last_modified_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_delete and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_delete_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_is_accessible and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_is_accessible_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_set_permission and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_IMPL_set_permission_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_open and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_open_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_write and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_write_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_read and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_read_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_close and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_close_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_seek and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_seek_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_get_file_pointer and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_get_file_pointer_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_set_length and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_set_length_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_IMPL_get_length_with_fd and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_get_length_with_fd_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_available and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_available_action(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Action requested by LLFS_File_IMPL_flush and executed asynchronously via async_worker. + * + * @param[in] job the context of the job, containing input/output parameters + */ +void LLFS_File_IMPL_flush_action(MICROEJ_ASYNC_WORKER_job_t* job); + +#ifdef __cplusplus + } +#endif + +#endif /* FS_HELPER_H */ diff --git a/bsp/projects/microej/fs/microej_fs.cmake b/bsp/projects/microej/fs/microej_fs.cmake new file mode 100644 index 0000000..2b83852 --- /dev/null +++ b/bsp/projects/microej/fs/microej_fs.cmake @@ -0,0 +1,13 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: BSD-3-Clause + +include_guard() +message("microej/fs component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/LLFS_File_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/fs_helper_fatfs.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLFS_impl.c +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) diff --git a/bsp/projects/microej/fs/src/LLFS_File_impl.c b/bsp/projects/microej/fs/src/LLFS_File_impl.c new file mode 100644 index 0000000..2f6f2ad --- /dev/null +++ b/bsp/projects/microej/fs/src/LLFS_File_impl.c @@ -0,0 +1,661 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLFS_File implementation with async worker. + * @author MicroEJ Developer Team + * @version 2.1.1 + * @date 26 April 2023 + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include +#include "sni.h" +#include "LLFS_impl.h" +#include "LLFS_File_impl.h" +#include "fs_configuration.h" +#include "fs_helper.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * Sanity check between the expected version of the configuration and the actual version of + * the configuration. + * If an error is raised here, it means that a new version of the CCO has been installed and + * the configuration fs_configuration.h must be updated based on the one provided + * by the new CCO version. + */ +#if FS_CONFIGURATION_VERSION != 1 + + #error "Version of the configuration file fs_configuration.h is not compatible with this implementation." + +#endif + +static int32_t LLFS_async_exec_write_read_job(int32_t file_id, uint8_t* data, int32_t offset, int32_t length, bool exec_write, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done); +static int32_t LLFS_async_exec_write_read_byte_job(int32_t file_id, int32_t data, bool exec_write, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done); +static int32_t LLFS_File_IMPL_open_on_done(uint8_t* path, uint8_t mode); +static int32_t LLFS_File_IMPL_write_on_done(int32_t file_id, uint8_t* data, int32_t offset, int32_t length); +static void LLFS_File_IMPL_write_byte_on_done(int32_t file_id, int32_t data); +static int32_t LLFS_File_IMPL_read_on_done(int32_t file_id, uint8_t* data, int32_t offset, int32_t length); +static int32_t LLFS_File_IMPL_read_byte_on_done(int32_t file_id); +static void LLFS_File_IMPL_close_on_done(int32_t file_id); +static void LLFS_File_IMPL_seek_on_done(int32_t file_id, int64_t n); +static int64_t LLFS_File_IMPL_get_file_pointer_on_done(int32_t file_id); +static void LLFS_File_IMPL_set_length_on_done(int32_t file_id, int64_t newLength); +static int64_t LLFS_File_IMPL_get_length_with_fd_on_done(int32_t file_id); +static int32_t LLFS_File_IMPL_available_on_done(int32_t file_id); +static void LLFS_File_IMPL_flush_on_done(int32_t file_id); + +int32_t LLFS_File_IMPL_open(uint8_t* path, uint8_t mode){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_File_IMPL_open); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return LLFS_NOK; + } + + FS_open_t* params = (FS_open_t*)job->params; + if(LLFS_set_path_param(path, (uint8_t*)¶ms->path) != LLFS_OK){ + SNI_throwNativeIOException(LLFS_NOK, "Path name too long"); + } + else{ + params->mode = mode; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_File_IMPL_open_action, (SNI_callback)LLFS_File_IMPL_open_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +int32_t LLFS_File_IMPL_write(int32_t file_id, uint8_t* data, int32_t offset, int32_t length){ + return LLFS_async_exec_write_read_job(file_id, data, offset, length, true, (SNI_callback)LLFS_File_IMPL_write, LLFS_File_IMPL_write_action, (SNI_callback)LLFS_File_IMPL_write_on_done); +} + +void LLFS_File_IMPL_write_byte(int32_t file_id, int32_t data){ + (void)LLFS_async_exec_write_read_byte_job(file_id, data, true, (SNI_callback)LLFS_File_IMPL_write_byte, LLFS_File_IMPL_write_action, (SNI_callback)LLFS_File_IMPL_write_byte_on_done); +} + +int32_t LLFS_File_IMPL_read(int32_t file_id, uint8_t* data, int32_t offset, int32_t length){ + return LLFS_async_exec_write_read_job(file_id, data, offset, length, false, (SNI_callback)LLFS_File_IMPL_read, LLFS_File_IMPL_read_action, (SNI_callback)LLFS_File_IMPL_read_on_done); +} + +int32_t LLFS_File_IMPL_read_byte(int32_t file_id){ + return LLFS_async_exec_write_read_byte_job(file_id, 0, false, (SNI_callback)LLFS_File_IMPL_read_byte, LLFS_File_IMPL_read_action, (SNI_callback)LLFS_File_IMPL_read_byte_on_done); +} + +void LLFS_File_IMPL_close(int32_t file_id) { + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_File_IMPL_close); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return; + } + + FS_close_t* params = (FS_close_t*)job->params; + params->file_id = file_id; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_File_IMPL_close_action, (SNI_callback)LLFS_File_IMPL_close_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return; + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); +} + +void LLFS_File_IMPL_seek(int32_t file_id, int64_t n){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_File_IMPL_seek); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return; + } + + FS_seek_t* params = (FS_seek_t*)job->params; + params->file_id = file_id; + params->n = n; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_File_IMPL_seek_action, (SNI_callback)LLFS_File_IMPL_seek_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return; + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return; +} + +int64_t LLFS_File_IMPL_get_file_pointer(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_File_IMPL_get_file_pointer); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return SNI_IGNORED_RETURNED_VALUE;; + } + + FS_getfp_t* params = (FS_getfp_t*)job->params; + params->file_id = file_id; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_File_IMPL_get_file_pointer_action, (SNI_callback)LLFS_File_IMPL_get_file_pointer_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE; + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +void LLFS_File_IMPL_set_length(int32_t file_id, int64_t newLength){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_File_IMPL_set_length); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return; + } + + FS_set_length_t* params = (FS_set_length_t*)job->params; + params->file_id = file_id; + params->length = newLength; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_File_IMPL_set_length_action, (SNI_callback)LLFS_File_IMPL_set_length_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return; + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return; +} + +int64_t LLFS_File_IMPL_get_length_with_fd(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_File_IMPL_get_length_with_fd); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return SNI_IGNORED_RETURNED_VALUE; + } + + FS_get_length_with_fd_t* params = (FS_get_length_with_fd_t*)job->params; + params->file_id = file_id; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_File_IMPL_get_length_with_fd_action, (SNI_callback)LLFS_File_IMPL_get_length_with_fd_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE; + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +int32_t LLFS_File_IMPL_available(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_File_IMPL_available); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return LLFS_NOK; + } + + FS_available_t* params = (FS_available_t*)job->params; + params->file_id = file_id; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_File_IMPL_available_action, (SNI_callback)LLFS_File_IMPL_available_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE; + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + + +void LLFS_File_IMPL_flush(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_File_IMPL_flush); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return; + } + + FS_flush_t* params = (FS_flush_t*)job->params; + params->file_id = file_id; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_File_IMPL_flush_action, (SNI_callback)LLFS_File_IMPL_flush_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return; + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); +} + +/** + * @brief Prepare and send an execution job to async_worker, called either from + * LLFS_File_IMPL_write or LLFS_File_IMPL_read. + * + * @param[in] file_id file identifier. + * @param[in] data buffer used for reading or writing operations. + * @param[in] offset the offset inside the buffer where the data has to be manipulated. + * @param[in] length buffer length. + * @param[in] exec_write true if the data buffer content need to be sent to the async_worker job, else false. + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * @param[in] action the function to execute asynchronously. + * @param[in] on_done the SNI_callback called when the job is done. + * + * @return SNI_IGNORED_RETURNED_VALUE on success, else a negative error code. + */ +static int32_t LLFS_async_exec_write_read_job(int32_t file_id, uint8_t* data, int32_t offset, int32_t length, bool exec_write, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done){ + + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, retry_function); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return LLFS_NOK; + } + + FS_write_read_t* params = (FS_write_read_t*)job->params; + + bool do_copy = exec_write; + int32_t result = SNI_retrieveArrayElements((int8_t *)data, offset, length, (int8_t*)¶ms->buffer, sizeof(params->buffer), (int8_t**)¶ms->data, (uint32_t *)¶ms->length, do_copy); + + if(result != SNI_OK){ + SNI_throwNativeIOException(result, "SNI_retrieveArrayElements: Internal error"); + } + else { + params->file_id = file_id; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, action, on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +/** + * @brief Prepare and send an execution job to async_worker, called either from + * LLFS_File_IMPL_write_byte or LLFS_File_IMPL_read_byte. + * + * @param[in] file_id file identifier. + * @param[in/out] data byte to be read/written. + * @param[in] exec_write true if the data buffer content need to be sent to the async_worker job, else false. + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * @param[in] action the function to execute asynchronously. + * @param[in] on_done the SNI_callback called when the job is done. + * + * @return SNI_IGNORED_RETURNED_VALUE on success, else a negative error code. + */ +static int32_t LLFS_async_exec_write_read_byte_job(int32_t file_id, int32_t data, bool exec_write, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, retry_function); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return LLFS_NOK; + } + + FS_write_read_t* params = (FS_write_read_t*)job->params; + + params->file_id = file_id; + params->data = (uint8_t*)¶ms->buffer; + params->length = sizeof(uint8_t); + if(exec_write == true){ + params->buffer[0] = (uint8_t)data; + } + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, action, on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_open is done. + * + * @param[in] path absolute path of file to open. + * @param[in] mode opening mode. + * + * @return LLFS_File_IMPL_open_action function return code. + */ +static int32_t LLFS_File_IMPL_open_on_done(uint8_t* path, uint8_t mode){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_open_t* params = (FS_open_t*)job->params; + + (void)path; + (void)mode; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_write is done. + * + * @param[in] file_id file identifier. + * @param[in] data buffer used for writing operations. + * @param[in] offset the offset inside the buffer where the data has to be manipulated. + * @param[in] length buffer length. + * + * @return LLFS_File_IMPL_write_action function return code. + */ +static int32_t LLFS_File_IMPL_write_on_done(int32_t file_id, uint8_t* data, int32_t offset, int32_t length){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_write_read_t* params = (FS_write_read_t*)job->params; + + (void)file_id; + (void)data; + (void)offset; + (void)length; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_read is done. + * + * @param[in] file_id file identifier. + * @param[out] data buffer used for reading operations. + * @param[in] offset the offset inside the buffer where the data has to be manipulated. + * @param[in] length buffer length. + * + * @return LLFS_File_IMPL_read_action function return code. + */ +static int32_t LLFS_File_IMPL_read_on_done(int32_t file_id, uint8_t* data, int32_t offset, int32_t length){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_write_read_t* params = (FS_write_read_t*)job->params; + + (void)file_id; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + else if(result != LLFS_EOF){ + int32_t release_result = SNI_flushArrayElements((int8_t*)data, offset, length, (int8_t*)params->data, result); + if(release_result != SNI_OK){ + SNI_throwNativeIOException(release_result, "SNI_flushArrayElements: Internal error"); + } + }else{ + // Successful: result hold the number of read bytes. + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_write_byte is done. + * + * @param[in] file_id file identifier. + * @param[in] data byte to be written. + * + * @return LLFS_File_IMPL_write_action function return code. + */ +static void LLFS_File_IMPL_write_byte_on_done(int32_t file_id, int32_t data){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_write_read_t* params = (FS_write_read_t*)job->params; + + (void)file_id; + (void)data; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_read_byte is done. + * + * @param[in] file_id file identifier. + * + * @return LLFS_File_IMPL_read_action function return code. + */ +static int32_t LLFS_File_IMPL_read_byte_on_done(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_write_read_t* params = (FS_write_read_t*)job->params; + + (void)file_id; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + else if(result == 1) { + // 1 byte read: return the read byte + result = (uint8_t)params->data[0]; + } + else if(result != LLFS_EOF) { + // Invalid value returned by the read_byte action + SNI_throwNativeIOException(result, "Internal error"); + } + else{ + // Successful: result hold the number of read bytes. + } + // else: result==LLFS_EOF: just return LLFS_EOF + + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_close is done. + * + * @param[in] file_id file identifier. + * + * @return LLFS_File_IMPL_close_action function return code. + */ +static void LLFS_File_IMPL_close_on_done(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_close_t* params = (FS_close_t*)job->params; + + (void)file_id; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_seek is done. + * + * @param[in] file_id file identifier. + * @param[in] n the new position of the file pointer. + * + * @return LLFS_File_IMPL_seek_action function return code. + */ +static void LLFS_File_IMPL_seek_on_done(int32_t file_id, int64_t n){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_seek_t* params = (FS_seek_t*)job->params; + + (void)file_id; + (void)n; + + if(params->result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_get_file_pointer is done. + * + * @param[in] file_id file identifier. + * + * @return LLFS_File_IMPL_get_file_pointer_on_done function return code. + */ +static int64_t LLFS_File_IMPL_get_file_pointer_on_done(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_getfp_t* params = (FS_getfp_t*)job->params; + + (void)file_id; + + int64_t result = params->result; + if(params->result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + return LLFS_NOK; + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_set_length is done. + * + * @param[in] file_id file identifier. + * @param[in] newLength the new length of the file. + * + * @return LLFS_File_IMPL_set_length_action function return code. + */ +static void LLFS_File_IMPL_set_length_on_done(int32_t file_id, int64_t newLength){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_set_length_t* params = (FS_set_length_t*)job->params; + + (void)file_id; + (void)newLength; + + if(params->result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_get_length_with_fd is done. + * + * @param[in] file_id file identifier. + * + * @return LLFS_IMPL_get_length_with_fd_action function return code. + */ +static int64_t LLFS_File_IMPL_get_length_with_fd_on_done(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_get_length_with_fd_t* params = (FS_get_length_with_fd_t*)job->params; + + (void)file_id; + + int64_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_available is done. + * + * @param[in] file_id file identifier. + * + * @return LLFS_File_IMPL_available_action function return code. + */ +static int32_t LLFS_File_IMPL_available_on_done(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_available_t* params = (FS_available_t*)job->params; + + (void)file_id; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_File_IMPL_flush is done. + * + * @param[in] file_id file identifier. + * + * @return LLFS_File_IMPL_flush_action function return code. + */ +static void LLFS_File_IMPL_flush_on_done(int32_t file_id){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_flush_t* params = (FS_flush_t*)job->params; + + (void)file_id; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); +} + + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/fs/src/LLFS_impl.c b/bsp/projects/microej/fs/src/LLFS_impl.c new file mode 100644 index 0000000..b19a032 --- /dev/null +++ b/bsp/projects/microej/fs/src/LLFS_impl.c @@ -0,0 +1,639 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLFS implementation with async worker. + * @author MicroEJ Developer Team + * @version 2.1.1 + * @date 26 April 2023 + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include +#include +#include "sni.h" +#include "LLFS_impl.h" +#include "fs_configuration.h" +#include "fs_helper.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * Sanity check between the expected version of the configuration and the actual version of + * the configuration. + * If an error is raised here, it means that a new version of the CCO has been installed and + * the configuration fs_configuration.h must be updated based on the one provided + * by the new CCO version. + */ +#if FS_CONFIGURATION_VERSION != 1 + + #error "Version of the configuration file fs_configuration.h is not compatible with this implementation." + +#endif + +#ifndef FS_CUSTOM_WORKER +/* Async worker task declaration ---------------------------------------------*/ +MICROEJ_ASYNC_WORKER_worker_declare(fs_worker, FS_WORKER_JOB_COUNT, FS_worker_param_t, FS_WAITING_LIST_SIZE); +OSAL_task_stack_declare(fs_worker_stack, FS_WORKER_STACK_SIZE); +#endif + +static MICROEJ_ASYNC_WORKER_job_t* LLFS_allocate_path_job(uint8_t* path, SNI_callback retry_function); +static int32_t LLFS_async_exec_path_job(uint8_t* path, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done); +static int32_t LLFS_async_exec_directory_job(int32_t directory_ID, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done); +static int32_t LLFS_IMPL_get_last_modified_on_done(uint8_t* path, LLFS_date_t* date); +static int32_t LLFS_IMPL_path_function_on_done(uint8_t* path); +static int64_t LLFS_IMPL_path64_function_on_done(uint8_t* path); +static int32_t LLFS_IMPL_create_on_done(uint8_t* path); +static int32_t LLFS_IMPL_read_directory_on_done(int32_t directory_ID, uint8_t* path); +static int32_t LLFS_IMPL_close_directory_on_done(int32_t directory_ID); +static int32_t LLFS_IMPL_rename_to_on_done(uint8_t* path, uint8_t* new_path); +static int64_t LLFS_IMPL_get_space_size_on_done(uint8_t* path, int32_t space_type); +static int32_t LLFS_IMPL_set_last_modified_on_done(uint8_t* path, LLFS_date_t* date); +static int32_t LLFS_IMPL_is_accessible_on_done(uint8_t* path, int32_t access); +static int32_t LLFS_IMPL_set_permission_on_done(uint8_t* path, int32_t access, int32_t enable, int32_t owner); +static int32_t LLFS_async_exec_path_result(void); + +void LLFS_IMPL_initialize(void){ +#ifndef FS_CUSTOM_WORKER + // cppcheck-suppress misra-c2012-11.8 // String casts conform to MICROEJ_ASYNC_WORKER_initialize function definitions. + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_initialize(&fs_worker, (uint8_t*)"MicroEJ FS", fs_worker_stack, FS_WORKER_PRIORITY); + if(status == MICROEJ_ASYNC_WORKER_INVALID_ARGS){ + SNI_throwNativeException(status, "Invalid argument for FS async worker"); + }else if (status == MICROEJ_ASYNC_WORKER_ERROR){ + SNI_throwNativeException(status, "Error while initializing FS async worker"); + }else{ + // Default case: MICROEJ_ASYNC_WORKER_OK + } +#endif + + llfs_init(); +} + +int32_t LLFS_IMPL_get_max_path_length(void){ + return FS_PATH_LENGTH; +} + +int32_t LLFS_IMPL_get_last_modified(uint8_t* path, LLFS_date_t* date){ + (void)date; + + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_get_last_modified, LLFS_IMPL_get_last_modified_action, (SNI_callback)LLFS_IMPL_get_last_modified_on_done); +} + +int32_t LLFS_IMPL_set_read_only(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_set_read_only, LLFS_IMPL_set_read_only_action, (SNI_callback)LLFS_IMPL_path_function_on_done); +} + +int32_t LLFS_IMPL_create(uint8_t* path){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_IMPL_create); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending + return LLFS_NOK; + } + + FS_path_operation_t* params = (FS_path_operation_t*)job->params; + if(LLFS_set_path_param(path, (uint8_t*)¶ms->path) != LLFS_OK){ + SNI_throwNativeIOException(LLFS_NOK, "Path name too long"); + } + else{ + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_IMPL_create_action, (SNI_callback)LLFS_IMPL_create_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +int32_t LLFS_IMPL_open_directory(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_open_directory, LLFS_IMPL_open_directory_action, (SNI_callback)LLFS_IMPL_path_function_on_done); +} + +int32_t LLFS_IMPL_read_directory(int32_t directory_ID, uint8_t* path){ + (void)path; + + return LLFS_async_exec_directory_job(directory_ID, (SNI_callback)LLFS_IMPL_read_directory, LLFS_IMPL_read_directory_action, (SNI_callback)LLFS_IMPL_read_directory_on_done); +} + +int32_t LLFS_IMPL_close_directory(int32_t directory_ID){ + return LLFS_async_exec_directory_job(directory_ID, (SNI_callback)LLFS_IMPL_close_directory, LLFS_IMPL_close_directory_action, (SNI_callback)LLFS_IMPL_close_directory_on_done); +} + +int32_t LLFS_IMPL_rename_to(uint8_t* path, uint8_t* new_path){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_IMPL_rename_to); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending. + return LLFS_NOK; + } + + FS_rename_to_t* params = (FS_rename_to_t*)job->params; + if((LLFS_set_path_param(path, (uint8_t*)¶ms->path) == LLFS_OK) && (LLFS_set_path_param(new_path, (uint8_t*)¶ms->new_path) == LLFS_OK)){ + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_IMPL_rename_to_action, (SNI_callback)LLFS_IMPL_rename_to_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +int64_t LLFS_IMPL_get_length(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_get_length, LLFS_IMPL_get_length_action, (SNI_callback)LLFS_IMPL_path64_function_on_done); +} + +int32_t LLFS_IMPL_exist(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_exist, LLFS_IMPL_exist_action, (SNI_callback)LLFS_IMPL_path_function_on_done); +} + +int64_t LLFS_IMPL_get_space_size(uint8_t* path, int32_t space_type){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_IMPL_get_space_size); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending. + return LLFS_NOK; + } + + FS_get_space_size* params = (FS_get_space_size*)job->params; + if(LLFS_set_path_param(path, (uint8_t*)¶ms->path) == LLFS_OK){ + params->space_type = space_type; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_IMPL_get_space_size_action, (SNI_callback)LLFS_IMPL_get_space_size_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +int32_t LLFS_IMPL_make_directory(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_make_directory, LLFS_IMPL_make_directory_action, (SNI_callback)LLFS_IMPL_path_function_on_done); +} + +int32_t LLFS_IMPL_is_hidden(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_is_hidden, LLFS_IMPL_is_hidden_action, (SNI_callback)LLFS_IMPL_path_function_on_done); +} + +int32_t LLFS_IMPL_is_directory(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_is_directory, LLFS_IMPL_is_directory_action, (SNI_callback)LLFS_IMPL_path_function_on_done); +} + +int32_t LLFS_IMPL_is_file(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_is_file, LLFS_IMPL_is_file_action, (SNI_callback)LLFS_IMPL_path_function_on_done); +} + +int32_t LLFS_IMPL_set_last_modified(uint8_t* path, LLFS_date_t* date){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_IMPL_set_last_modified); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending. + return LLFS_NOK; + } + + FS_last_modified_t* params = (FS_last_modified_t*)job->params; + if(LLFS_set_path_param(path, (uint8_t*)¶ms->path) == LLFS_OK){ + params->date = *date; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_IMPL_set_last_modified_action, (SNI_callback)LLFS_IMPL_set_last_modified_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +int32_t LLFS_IMPL_delete(uint8_t* path){ + return LLFS_async_exec_path_job(path, (SNI_callback)LLFS_IMPL_delete, LLFS_IMPL_delete_action, (SNI_callback)LLFS_IMPL_path_function_on_done); +} + +int32_t LLFS_IMPL_is_accessible(uint8_t* path, int32_t access){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_IMPL_is_accessible); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending. + return LLFS_NOK; + } + + FS_is_accessible_t* params = (FS_is_accessible_t*)job->params; + if(LLFS_set_path_param(path, (uint8_t*)¶ms->path) == LLFS_OK){ + params->access = access; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_IMPL_is_accessible_action, (SNI_callback)LLFS_IMPL_is_accessible_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +int32_t LLFS_IMPL_set_permission(uint8_t* path, int32_t access, int32_t enable, int32_t owner){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, (SNI_callback)LLFS_IMPL_set_permission); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending. + return LLFS_NOK; + } + + FS_set_permission_t* params = (FS_set_permission_t*)job->params; + if(LLFS_set_path_param(path, (uint8_t*)¶ms->path) == LLFS_OK){ + params->access = access; + params->enable = enable; + params->owner = owner; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, LLFS_IMPL_set_permission_action, (SNI_callback)LLFS_IMPL_set_permission_on_done); + if(status == MICROEJ_ASYNC_WORKER_OK){ + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } // else an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + } + + // Error + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; +} + +int32_t LLFS_set_path_param(uint8_t* path, uint8_t* path_param){ + int32_t path_length = SNI_getArrayLength(path); + if(path_length > FS_PATH_LENGTH){ + // Path too long for the buffer + SNI_throwNativeException(LLFS_NOK, "Path length is too long"); + return LLFS_NOK; + } + // cppcheck-suppress misra-c2012-17.7 // Return value does not require checking. + memcpy(path_param, path, path_length); + return LLFS_OK; +} + +/** + * @brief Allocates an async_worker job containing a generic file path buffer. + * + * @param[in] path absolute path of file. + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * + * @return an allocated job object or NULL if the allocation fails. + */ +static MICROEJ_ASYNC_WORKER_job_t* LLFS_allocate_path_job(uint8_t* path, SNI_callback retry_function){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, retry_function); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending. + return NULL; + } + + FS_path_operation_t* params = (FS_path_operation_t*)job->params; + if(LLFS_set_path_param(path, (uint8_t*)¶ms->path) != LLFS_OK){ + // Path name too long + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return NULL; + } + + return job; +} + +/** + * @brief Prepare and send an execution job to async_worker, called either from + * LLFS_IMPL_get_last_modified, LLFS_IMPL_set_read_only, + * LLFS_IMPL_open_directory, LLFS_IMPL_get_length, + * LLFS_IMPL_exist, LLFS_IMPL_make_directory, + * LLFS_IMPL_is_hidden, LLFS_IMPL_is_directory, + * LLFS_IMPL_is_file or LLFS_IMPL_delete. + * + * @param[in] path absolute path of file. + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * @param[in] action the function to execute asynchronously. + * @param[in] on_done the SNI_callback called when the job is done. + * + * @return SNI_IGNORED_RETURNED_VALUE on success, else a negative error code. + */ +static int32_t LLFS_async_exec_path_job(uint8_t* path, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done){ + MICROEJ_ASYNC_WORKER_job_t* job = LLFS_allocate_path_job(path, retry_function); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending. + return LLFS_NOK; + } + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, action, on_done); + if(status != MICROEJ_ASYNC_WORKER_OK){ + // an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; + } + else { + // Wait for the action to be done + return SNI_IGNORED_RETURNED_VALUE;//returned value not used + } +} + +/** + * @brief Prepare and send an execution job to async_worker, called either from + * LLFS_IMPL_read_directory or LLFS_IMPL_close_directory. + * + * @param[in] directory_ID the directory ID. + * @param[in] retry_function if the current Java thread has been suspended, this function is called when it is resumed. + * @param[in] action the function to execute asynchronously. + * @param[in] on_done the SNI_callback called when the job is done. + * + * @return SNI_IGNORED_RETURNED_VALUE on success, else a negative error code. + */ +static int32_t LLFS_async_exec_directory_job(int32_t directory_ID, SNI_callback retry_function, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&fs_worker, retry_function); + if(job == NULL){ + // No job available, either: + // - wait for a job to be available and this function to be executed again, + // - or an exception is pending. + return LLFS_NOK; + } + + FS_directory_operation_t* params = (FS_directory_operation_t*)job->params; + params->directory_ID = directory_ID; + + MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&fs_worker, job, action, on_done); + + if(status != MICROEJ_ASYNC_WORKER_OK){ + // an error occurred and MICROEJ_ASYNC_WORKER_async_exec has thrown a SNI exception + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return LLFS_NOK; + } + else { + // Wait for the action to be done + return LLFS_OK;//returned value not used + } +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_get_last_modified is done. + * + * @param[in] path absolute path of file. + * @param[out] date the structure where the date is stored. + * + * @return LLFS_IMPL_get_last_modified_action function return code. + */ +static int32_t LLFS_IMPL_get_last_modified_on_done(uint8_t* path, LLFS_date_t* date){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_last_modified_t* params = (FS_last_modified_t*)job->params; + + (void)path; + + int32_t result = params->result; + if(result == LLFS_OK){ + *date = params->date; + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_set_read_only, + * LLFS_IMPL_open_directory, LLFS_IMPL_exist, + * LLFS_IMPL_make_directory, LLFS_IMPL_is_hidden, + * LLFS_IMPL_is_directory, LLFS_IMPL_is_file or + * LLFS_IMPL_delete is done. + * + * @param[in] path absolute path of file. + * + * @return LLFS_IMPL_set_read_only_action, + * LLFS_IMPL_open_directory_action, LLFS_IMPL_exist_action, + * LLFS_IMPL_make_directory_action, LLFS_IMPL_is_hidden_action, + * LLFS_IMPL_is_directory_action, LLFS_IMPL_is_file_action or + * LLFS_IMPL_delete_action function return code. + */ +static int32_t LLFS_IMPL_path_function_on_done(uint8_t* path){ + (void)path; + + return LLFS_async_exec_path_result(); +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_get_length is done. + * + * @param[in] path absolute path of file. + * + * @return LLFS_IMPL_get_length_action function return code. + */ +static int64_t LLFS_IMPL_path64_function_on_done(uint8_t* path){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_path64_operation_t* params = (FS_path64_operation_t*)job->params; + + (void)path; + + int64_t result = params->result; + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_create is done. + * + * @param[in] path absolute path of file. + * + * @return LLFS_IMPL_create_action function return code. + */ +static int32_t LLFS_IMPL_create_on_done(uint8_t* path){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_create_t* params = (FS_create_t*)job->params; + + (void)path; + + int32_t result = params->result; + if(result == LLFS_NOK){ + // Exception + SNI_throwNativeIOException(params->error_code, params->error_message); + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_read_directory is done. + * + * @param[in] directory_ID the directory ID. + * @param[out] path path where to store the next available file. + * + * @return LLFS_IMPL_read_directory_action function return code. + */ +static int32_t LLFS_IMPL_read_directory_on_done(int32_t directory_ID, uint8_t* path){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_read_directory_t* params = (FS_read_directory_t*)job->params; + + (void)directory_ID; + + int32_t result = params->result; + if(result == LLFS_OK){ + // Copy back the read path + int32_t java_path_length = SNI_getArrayLength(path); + int32_t path_length = strlen((char *)params->path) + (size_t)1;//add 1 for the terminating null byte ('\0'). + if(java_path_length >= path_length){ + // Buffer large enough for the path + // cppcheck-suppress misra-c2012-17.7 // Return value does not require checking. + memcpy(path, params->path, path_length); + } + else { + // Path too long for the buffer + result = LLFS_NOK; + } + } + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_close_directory is done. + * + * @param[in] directory_ID the directory ID. + * + * @return LLFS_IMPL_close_directory_action function return code. + */ +static int32_t LLFS_IMPL_close_directory_on_done(int32_t directory_ID){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_close_directory_t* params = (FS_close_directory_t*)job->params; + + (void)directory_ID; + + int32_t result = params->result; + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_rename_to is done. + * + * @param[in] path absolute path of file to modify. + * @param[in] new_path new absolute path of file. + * + * @return LLFS_IMPL_rename_to_action function return code. + */ +static int32_t LLFS_IMPL_rename_to_on_done(uint8_t* path, uint8_t* new_path){ + (void)path; + (void)new_path; + + return LLFS_async_exec_path_result(); +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_get_space_size is done. + * + * @param[in] path absolute path of file in the require partition. + * @param[in] space_type space type. + * + * @return LLFS_IMPL_get_space_size_action function return code. + */ +static int64_t LLFS_IMPL_get_space_size_on_done(uint8_t* path, int32_t space_type){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_get_space_size* params = (FS_get_space_size*)job->params; + + (void)path; + (void)space_type; + + int64_t result = params->result; + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return result; +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_set_last_modified is done. + * + * @param[in] path absolute path of file to modified. + * @param[in] date the new date of the file. + * + * @return LLFS_IMPL_set_last_modified_action function return code. + */ +static int32_t LLFS_IMPL_set_last_modified_on_done(uint8_t* path, LLFS_date_t* date){ + (void)path; + (void)date; + + return LLFS_async_exec_path_result(); +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_is_accessible is done. + * + * @param[in] path absolute path of file to modified. + * @param[in] access access type to be checked. + * + * @return LLFS_IMPL_is_accessible_action function return code. + */ +static int32_t LLFS_IMPL_is_accessible_on_done(uint8_t* path, int32_t access){ + (void)path; + (void)access; + + return LLFS_async_exec_path_result(); +} + +/** + * @brief The SNI_callback called when the async_worker job requested by LLFS_IMPL_set_permission is done. + * + * @param[in] path absolute path of file to modified. + * @param[in] access access type to set. + * @param[in] enable permission enable or disable. + * @param[in] owner permission owner. + * + * @return LLFS_IMPL_set_permission_action function return code. + */ +static int32_t LLFS_IMPL_set_permission_on_done(uint8_t* path, int32_t access, int32_t enable, int32_t owner){ + (void)path; + (void)access; + (void)enable; + (void)owner; + + return LLFS_async_exec_path_result(); +} + +/** + * @brief Unified handling for SNI_callback, called via + * LLFS_IMPL_path_function_on_done, LLFS_IMPL_rename_to_on_done, + * LLFS_IMPL_set_last_modified_on_done, LLFS_IMPL_is_accessible_on_done and + * LLFS_IMPL_set_permission_on_done functions. + * + * @return @see function callers return code. + */ +static int32_t LLFS_async_exec_path_result(void){ + MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + FS_path_operation_t* params = (FS_path_operation_t*)job->params; + + int32_t result = params->result; + MICROEJ_ASYNC_WORKER_free_job(&fs_worker, job); + return result; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/fs/src/fs_helper_fatfs.c b/bsp/projects/microej/fs/src/fs_helper_fatfs.c new file mode 100644 index 0000000..a5fe290 --- /dev/null +++ b/bsp/projects/microej/fs/src/fs_helper_fatfs.c @@ -0,0 +1,777 @@ +/* + * C + * + * Copyright 2020-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + * Copyright 2024 NXP + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +/** + * @file + * @brief FatFs helper for LLFS. + * @author MicroEJ Developer Team + * @version 2.1.0 + */ + +#include +#include +#include "ff.h" +#include "fs_helper.h" +#include "microej_async_worker.h" +#include "microej_pool.h" +#include "LLFS_File_impl.h" +#include "diskio.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** @brief define the amount of file in private pool module */ +#define FS_MAX_NUMBER_OF_FILE_IN_POOL (FF_FS_LOCK) + +/** @brief define the amount of dir in private pool module */ +#define FS_MAX_NUMBER_OF_DIR_IN_POOL (FF_FS_LOCK) + +/** @ brief private pool file */ +static FIL gpst_pool_file[FS_MAX_NUMBER_OF_FILE_IN_POOL]; +static POOL_item_status_t gpst_pool_file_item_status[FS_MAX_NUMBER_OF_FILE_IN_POOL]; +static POOL_ctx_t gst_pool_file_ctx = +{ + gpst_pool_file, + gpst_pool_file_item_status, + sizeof(FIL), + sizeof(gpst_pool_file)/sizeof(FIL) +}; + +/** @brief private pool directory */ +static FF_DIR gpst_pool_dir[FS_MAX_NUMBER_OF_DIR_IN_POOL]; +static POOL_item_status_t gpst_pool_dir_item_status[FS_MAX_NUMBER_OF_DIR_IN_POOL]; +static POOL_ctx_t gst_pool_dir_ctx = +{ + gpst_pool_dir, + gpst_pool_dir_item_status, + sizeof(FF_DIR), + sizeof(gpst_pool_dir)/sizeof(FF_DIR) +}; + +void LLFS_IMPL_get_last_modified_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_last_modified_t* param = (FS_last_modified_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + LLFS_date_t* out_date = ¶m->date; + + res = f_stat((TCHAR*)path, &fno); + if (FR_OK != res) { + param->result = LLFS_NOK; + } else { + out_date->second = (int32_t) ((fno.ftime & 31) * 2); + out_date->minute = (int32_t) ((fno.ftime >> 5) & 63); + out_date->hour = (int32_t) (fno.ftime >> 11); + out_date->day = (int32_t) (fno.fdate & 31); + out_date->month = (int32_t) ((fno.fdate >> 5) & 15); + out_date->year = (int32_t) ((fno.fdate >> 9) + 1980); + param->result = LLFS_OK; + } + + LLFS_DEBUG_TRACE("[%s:%u] timestamp get : %ld/%02ld/%02ld, %02ld:%02ld:%02ld\n (err %d)\n", __func__, __LINE__, + out_date->year, out_date->month, out_date->day, out_date->hour, out_date->minute, out_date->second, res); +} + +void LLFS_IMPL_set_read_only_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path_operation_t* param = (FS_path_operation_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_stat((TCHAR*)path, &fno); + if ((res != FR_OK) || (fno.fattrib & AM_DIR)) { + /* If an error occurs or the file is directory returns error */ + param->result = LLFS_NOK; + } else { + res = f_chmod((TCHAR*)path, AM_RDO, AM_RDO); + if (res != FR_OK) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] readonly set on %s (err %d)\n", __func__, __LINE__, path, res); +} + +void LLFS_IMPL_create_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_create_t* param = (FS_create_t*) job->params; + FIL fp = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_open(&fp, (TCHAR*)path, FA_CREATE_NEW); + if (res == FR_OK) { + res = f_close(&fp); + if (res == FR_OK) { + param->result = LLFS_OK; + } else { + param->result = LLFS_NOK; + param->error_code = res; + param->error_message = "f_close failed"; + } + } else if (res == FR_EXIST) { + param->result = LLFS_NOT_CREATED; + param->error_code = res; + param->error_message = "file exists"; + } else { + param->result = LLFS_NOT_CREATED; + param->error_code = res; + param->error_message = "f_open failed"; + } + + LLFS_DEBUG_TRACE("[%s:%u] create file %s (err %d)\n", __func__, __LINE__, path, res); +} + +void LLFS_IMPL_open_directory_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path_operation_t* param = (FS_path_operation_t*) job->params; + FF_DIR * pdir; + FRESULT res = FR_OK; + POOL_status_t pool_res; + + uint8_t* path = (uint8_t*)¶m->path; + + pool_res = POOL_reserve_f(&gst_pool_dir_ctx, (void**)&pdir); + if (pool_res != POOL_NO_ERROR) { + param->result = LLFS_NOK; + } else { + res = f_opendir(pdir, (TCHAR*)path); + if (res == FR_OK) { + param->result = (int32_t)pdir; + } else { + POOL_free_f(&gst_pool_dir_ctx, (void*)pdir); + param->result = LLFS_NOK; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] open dir %s fd %ld (err %d)\n", __func__, __LINE__, path, param->result, res); +} + +void LLFS_IMPL_read_directory_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_read_directory_t* param = (FS_read_directory_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + int32_t directory_ID = param->directory_ID; + uint8_t* path = (uint8_t*)¶m->path; + res = f_readdir((FF_DIR*)directory_ID, &fno); + if ((res != FR_OK) || (fno.fname[0] == 0)) { + param->result = LLFS_NOK; + } else { + // cppcheck-suppress misra-c2012-17.7 // Return value does not require checking. + strcpy((char*)path, (char*)(fno.fname)); + param->result = LLFS_OK; + } + + LLFS_DEBUG_TRACE("[%s:%u] read dir %ld return %s (err %d)\n", __func__, __LINE__, directory_ID, path, res); +} + +void LLFS_IMPL_close_directory_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_close_directory_t* param = (FS_close_directory_t*) job->params; + FRESULT res = FR_OK; + + int32_t directory_ID = param->directory_ID; + + res = f_closedir((FF_DIR*)directory_ID); + if (res != FR_OK) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + + // cppcheck-suppress misra-c2012-11.6 // directory_ID type is received from SNI. + POOL_free_f(&gst_pool_dir_ctx, (void*)directory_ID); + + LLFS_DEBUG_TRACE("[%s:%u] close dir %ld (err %d)\n", __func__, __LINE__, directory_ID, res); +} + +void LLFS_IMPL_rename_to_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_rename_to_t* param = (FS_rename_to_t*) job->params; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + uint8_t* new_path = (uint8_t*)¶m->new_path; + + res = f_rename((TCHAR*)path, (TCHAR*)new_path); + if (res != FR_OK) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + + LLFS_DEBUG_TRACE("[%s:%u] rename : old name %s, new name %s (err %d)\n", __func__, __LINE__, path, new_path, res); +} + +void LLFS_IMPL_get_length_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path64_operation_t* param = (FS_path64_operation_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_stat((TCHAR*)path, &fno); + if (res == FR_OK) { + param->result = fno.fsize; + } else if (res == FR_NO_FILE) { + param->result = 0; + } else { + param->result = LLFS_NOK; + } + + LLFS_DEBUG_TRACE("[%s:%u] length of %s : %lld bytes (err %d)\n", __func__, __LINE__, path, param->result, res); +} + +void LLFS_IMPL_exist_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path_operation_t* param = (FS_path_operation_t*) job->params; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_stat((TCHAR*)path, NULL); + if (res != FR_OK) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + + LLFS_DEBUG_TRACE("[%s:%u] exist file %s (err %d)\n", __func__, __LINE__, path, res); +} + +void LLFS_IMPL_get_space_size_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_get_space_size* param = (FS_get_space_size*) job->params; + FATFS* fs; + DWORD dw_free_cluster; + WORD ssize = FF_MAX_SS; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + int32_t space_type = param->space_type; + + res = f_getfree((TCHAR*)path, &dw_free_cluster, &fs); + if (res != FR_OK) { + param->result = LLFS_NOK; + } else if (res == FR_NO_PATH) { + param->result = 0; + } else { +// cppcheck-suppress misra-c2012-20.9 // Defined by FatFS. +#if FF_MAX_SS != FF_MIN_SS + if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &ssize) != RES_OK) { + param->result = LLFS_NOK; + } else { +#endif + switch (space_type) { + case LLFS_FREE_SPACE: + case LLFS_USABLE_SPACE: + param->result = (dw_free_cluster * fs->csize) * ssize; + break; + case LLFS_TOTAL_SPACE: + /* minus 2 -> one for boot and one reserved */ + param->result = ((fs->n_fatent - 2) * fs->csize) * ssize; + break; + default: + param->result = LLFS_NOK; + break; + } +// cppcheck-suppress misra-c2012-20.9 // Defined by FatFS. +#if FF_MAX_SS != FF_MIN_SS + } +#endif + } + + LLFS_DEBUG_TRACE("[%s:%u] get space type %ld on %s : %lld bytes (err %d)\n", __func__, __LINE__, space_type, path, param->result, res); +} + +void LLFS_IMPL_make_directory_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path_operation_t* param = (FS_path_operation_t*) job->params; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_mkdir((TCHAR*)path); + if (FR_OK != res) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + + LLFS_DEBUG_TRACE("[%s:%u] create dir %s (err %d)\n", __func__, __LINE__, path, res); +} + +void LLFS_IMPL_is_hidden_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path_operation_t* param = (FS_path_operation_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_stat((TCHAR*)path, &fno); + if (FR_OK != res) { + param->result = LLFS_NOK; + } else { + if ((fno.fattrib & AM_HID) != 0x0) { + param->result = LLFS_OK; + } else { + param->result = LLFS_NOK; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] %s is hidden ? (err %d)\n", __func__, __LINE__, path, res); +} + +void LLFS_IMPL_is_directory_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path_operation_t* param = (FS_path_operation_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_stat((TCHAR*)path, &fno); + if (FR_OK != res) { + param->result = LLFS_NOK; + } else { + if ((fno.fattrib & AM_DIR) != 0x0) { + param->result = LLFS_OK; + } else { + param->result = LLFS_NOK; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] %s is directory ? (err %d)\n", __func__, __LINE__, path, res); +} + +void LLFS_IMPL_is_file_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path_operation_t* param = (FS_path_operation_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_stat((TCHAR*)path, &fno); + if (FR_OK != res) { + param->result = LLFS_NOK; + } else { + if ((fno.fattrib & AM_DIR) != 0x0) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] %s is file ? (err %d)\n", __func__, __LINE__, path, res); +} + +void LLFS_IMPL_set_last_modified_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_last_modified_t* param = (FS_last_modified_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + LLFS_date_t* new_date = ¶m->date; + + fno.fdate = (WORD)(((new_date->year - 1980) * 512U) | (new_date->month * 32U) | new_date->day); + fno.ftime = (WORD)((new_date->hour * 2048U) | (new_date->minute * 32U) | (new_date->second / 2U)); + + res = f_utime((TCHAR*)path, &fno); + if (FR_OK != res) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + + LLFS_DEBUG_TRACE("[%s:%u] timestamp set : %ld/%02ld/%02ld, %02ld:%02ld:%02ld\n (err %d)\n", __func__, __LINE__, + new_date->year, new_date->month, new_date->day, new_date->hour, new_date->minute, new_date->second, res); +} + +void LLFS_IMPL_delete_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_path_operation_t* param = (FS_path_operation_t*) job->params; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + + res = f_unlink((TCHAR*)path); + if (FR_OK != res) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + + LLFS_DEBUG_TRACE("[%s:%u] delete %s (err %d)\n", __func__, __LINE__, path, res); +} + +void LLFS_IMPL_is_accessible_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_is_accessible_t* param = (FS_is_accessible_t*) job->params; + FILINFO fno = {0}; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + int32_t checked_access = param->access; + + res = f_stat((TCHAR*)path, &fno); + if (res != FR_OK) { + param->result = LLFS_NOK; + } else { + switch (checked_access) { + case LLFS_ACCESS_WRITE: + if ((fno.fattrib & AM_RDO) != 0x0) { + param->result = LLFS_NOK; + } else { + param->result = LLFS_OK; + } + break; + /* FatFs doesn't support other permissions so return always ok */ + case LLFS_ACCESS_READ: + param->result = LLFS_OK; + break; + case LLFS_ACCESS_EXECUTE: + param->result = LLFS_OK; + break; + default: + param->result = LLFS_NOK; + break; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] %s is accessible ? access %ld (err %d)\n", __func__, __LINE__, path, checked_access, res); +} + +void LLFS_IMPL_set_permission_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_set_permission_t* param = (FS_set_permission_t*) job->params; + FILINFO fno = {0}; + BYTE attr; + FRESULT res = FR_OK; + + uint8_t* path = (uint8_t*)¶m->path; + int32_t access = param->access; + int32_t enable = param->enable; + + res = f_stat((TCHAR*)path, &fno); + if ((res != FR_OK) || (fno.fattrib & AM_DIR)) { + /* If an error occurs or the file is directory returns error */ + param->result = LLFS_NOK; + } else { + attr = enable ? AM_RDO : 0; + switch (access) { + case LLFS_ACCESS_WRITE: + /* FatFs doesn't identify the owner */ + res = f_chmod((TCHAR*)path, attr, AM_RDO); + if (res == FR_OK) { + param->result = LLFS_OK; + } else { + param->result = LLFS_NOK; + } + break; + /* FatFs doesn't support other permissions so return always ok */ + case LLFS_ACCESS_READ: + param->result = LLFS_OK; + break; + case LLFS_ACCESS_EXECUTE: + param->result = LLFS_OK; + break; + default: + param->result = LLFS_NOK; + break; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] set permission %ld for %s as %ld (err %d)\n", __func__, __LINE__, access, path, enable, res); +} + +void LLFS_File_IMPL_open_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_open_t* param = (FS_open_t*) job->params; + FIL * fp; + FRESULT res = FR_OK; + POOL_status_t pool_res; + BYTE b_internal_mode = 0xFF; + + uint8_t* path = (uint8_t*)¶m->path; + uint8_t mode = param->mode; + + /* Map input mode to FatFs mode */ + switch(mode) { + case LLFS_FILE_MODE_APPEND: + b_internal_mode = FA_WRITE | FA_OPEN_APPEND; + break; + case LLFS_FILE_MODE_READ: + b_internal_mode = FA_READ | FA_OPEN_EXISTING; + break; + case LLFS_FILE_MODE_WRITE: + b_internal_mode = FA_WRITE | FA_CREATE_ALWAYS; + break; + case LLFS_FILE_MODE_READ_WRITE: + case LLFS_FILE_MODE_READ_WRITE_DATA_SYNC: + case LLFS_FILE_MODE_READ_WRITE_SYNC: + b_internal_mode = FA_READ | FA_WRITE | FA_OPEN_ALWAYS; + break; + default: + param->error_code = mode; + param->error_message = "Invalid opening mode"; + return; + } + + pool_res = POOL_reserve_f(&gst_pool_file_ctx, (void**)&fp); + if (pool_res != POOL_NO_ERROR) { + param->result = LLFS_NOK; + param->error_code = pool_res; + param->error_message = "POOL_reserve_f failed"; + } else { + res = f_open(fp, (TCHAR*)path, b_internal_mode); + if (res != FR_OK) { + POOL_free_f(&gst_pool_file_ctx, (void*)fp); + param->result = LLFS_NOK; + param->error_code = res; + param->error_message = "f_open failed"; + } else { + /* An f_lseek() following f_open() is no longer needed if FA_OPEN_APPEND mode, since FatFs R0.12a */ + param->result = (int32_t)fp; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] open file %s in %c mode, fd %ld (err %d)\n", __func__, __LINE__, path, mode, param->result, res); +} + +void LLFS_File_IMPL_write_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_write_read_t* param = (FS_write_read_t*) job->params; + unsigned int byteswritten; + FRESULT res = FR_OK; + + FIL* fd = (FIL*)param->file_id; + uint8_t* data = param->data; + int32_t length = param->length; + + res = f_write(fd, (void*)data, length, &byteswritten); + if (res != FR_OK) { + param->result = LLFS_NOK; + param->error_code = res; + param->error_message = "f_write failed"; + } else { + param->result = (int32_t)byteswritten; + } + + LLFS_DEBUG_TRACE("[%s:%u] written %ld bytes to file %ld (err %d)\n", __func__, __LINE__, param->result, (int32_t)fd, res); +} + +void LLFS_File_IMPL_read_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_write_read_t* param = (FS_write_read_t*) job->params; + unsigned int bytesread; + FRESULT res = FR_OK; + + FIL* fd = (FIL*)param->file_id; + uint8_t* data = param->data; + int32_t length = param->length; + + res = f_read(fd, (void*)data, length, &bytesread); + if (res != FR_OK) { + param->result = LLFS_NOK; + param->error_code = res; + param->error_message = "f_read failed"; + } else { + if (bytesread == (unsigned int)0) { + param->result = LLFS_EOF; + } else { + param->result = (int32_t)bytesread; + } + } + + LLFS_DEBUG_TRACE("[%s:%u] read %ld bytes from file %ld (err %d)\n", __func__, __LINE__, param->result, (int32_t)fd, res); +} + +void LLFS_File_IMPL_close_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_close_t* param = (FS_close_t*) job->params; + FRESULT res = FR_OK; + + FIL* fd = (FIL*)param->file_id; + + res = f_close(fd); + if (res != FR_OK) { + param->result = LLFS_NOK; + param->error_code = res; + param->error_message = "f_close failed"; + } else { + param->result = LLFS_OK; + } + + POOL_free_f(&gst_pool_file_ctx, (void*)fd); + + LLFS_DEBUG_TRACE("[%s:%u] close file %ld (status %ld err %d)\n", __func__, __LINE__, (int32_t)fd, param->result, res); +} + +static FRESULT seek(FIL* fd, QWORD n, FSIZE_t *pos) { + // Convert given offset in a type accepted by f_lseek + *pos = n; + + // Check if the conversion from long long int to FSIZE_t is correct + // cppcheck-suppress knownConditionTrueFalse // Data types depend on the platform architecture. + if (*pos != n) { + // An overflow occurs, saturate the value +// cppcheck-suppress misra-c2012-20.9 // Defined by FatFS. +#if FF_FS_EXFAT + *pos = INT64_MAX; +#else + *pos = INT32_MAX; +#endif + } + + return f_lseek(fd, *pos); +} + +void LLFS_File_IMPL_seek_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_seek_t* param = (FS_seek_t*) job->params; + FIL* fd = (FIL*)param->file_id; + FSIZE_t pos = 0; + + if (param->n < 0) { + param->result = LLFS_NOK; + param->error_code = FR_INVALID_PARAMETER; + param->error_message = "f_lseek failed"; + } else { + FRESULT res = seek(fd, param->n, &pos); + if (res != FR_OK) { + param->result = LLFS_NOK; + param->error_code = res; + param->error_message = "f_lseek failed"; + } + } +// cppcheck-suppress misra-c2012-20.9 // Defined by FatFS. +#if FF_FS_EXFAT + LLFS_DEBUG_TRACE("[%s:%u] seek to %lld on %ld (status %ld)\n", __func__, __LINE__, pos, (int32_t)fd, param->result); +#else + LLFS_DEBUG_TRACE("[%s:%u] seek to %ld on %ld (status %ld)\n", __func__, __LINE__, pos, (int32_t)fd, param->result); +#endif +} + +void LLFS_File_IMPL_get_file_pointer_action(MICROEJ_ASYNC_WORKER_job_t* job) { + FS_getfp_t* param = (FS_getfp_t*) job->params; + FIL* fd = (FIL*)param->file_id; + param->result = f_tell(fd);; + + if (param->result < 0) { + // Error occurred + param->error_code = param->result; + param->result = LLFS_NOK; + param->error_message = "f_tell failed"; + } + +#ifdef LLFS_DEBUG + LLFS_DEBUG_TRACE("[%s:%u] get file pointer file %ld (status %lld)\n",__func__, __LINE__, (int32_t) fd, param->result); +#endif +} + +void LLFS_File_IMPL_set_length_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_set_length_t* param = (FS_set_length_t*) job->params; + FRESULT res = FR_OK; + FSIZE_t pos = 0; + FIL* fd = (FIL*)param->file_id; + FSIZE_t oldSize = f_size(fd); + FSIZE_t oldPos = f_tell(fd); + DWORD newSize = param->length; + + // First we do a seek + res = seek(fd, newSize, &pos); + if ((res == FR_OK) && (f_tell(fd) == pos)) { + if (oldSize > newSize) { + // second if the new size is less than the old size we do a truncate + res = f_truncate(fd); + } + if ((res == FR_OK) && (oldPos < newSize)) { + // third reset the file pointer if the old pos is less than the new length + res = f_lseek(fd, oldPos); + } + } + + if (res != FR_OK) { + param->result = LLFS_NOK; + param->error_code = res; + param->error_message = "set length failed"; + } + + LLFS_DEBUG_TRACE("[%s:%u] set length to %ld on %ld size=%ld (status %ld)\n", __func__, __LINE__, newSize, (int32_t)fd, f_size(fd), param->result); +} + + +void LLFS_File_IMPL_get_length_with_fd_action(MICROEJ_ASYNC_WORKER_job_t* job) { + FS_get_length_with_fd_t* param = (FS_get_length_with_fd_t*) job->params; + FIL* fd = (FIL*)param->file_id; + param->result = f_size(fd); +// cppcheck-suppress misra-c2012-20.9 // Defined by FatFS. +#if FF_FS_EXFAT + LLFS_DEBUG_TRACE("[%s:%u] get length with fd on %lld length=%ld \n", __func__, __LINE__, (int32_t)fd, param->result); +#else + LLFS_DEBUG_TRACE("[%s:%u] get length with fd on %ld length=%ld \n", __func__, __LINE__, (int32_t)fd, param->result); +#endif +} + +void LLFS_File_IMPL_available_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_available_t* param = (FS_available_t*) job->params; + + FIL* fd = (FIL*)param->file_id; + + DWORD currentPtr = f_tell(fd); + DWORD size = f_size(fd); + + if (currentPtr > size) { + param->result = 0; + } else { + param->result = size - currentPtr; + } + + LLFS_DEBUG_TRACE("[%s:%u] available %ld bytes on %ld\n", __func__, __LINE__, param->result, (int32_t)fd); +} + +void LLFS_File_IMPL_flush_action(MICROEJ_ASYNC_WORKER_job_t* job) { + + FS_flush_t* param = (FS_flush_t*) job->params; + FRESULT res = FR_OK; + + FIL* fd = (FIL*)param->file_id; + + res = f_sync(fd); + if (res != FR_OK) { + param->result = LLFS_NOK; + param->error_code = res; + param->error_message = "f_sync failed"; + } else { + param->result = LLFS_OK; + } + + LLFS_DEBUG_TRACE("[%s:%u] flush file %ld (status %ld err %d)\n", __func__, __LINE__, (int32_t)fd, param->result, res); +} + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/gpio/inc/LLGPIO_mux.h b/bsp/projects/microej/gpio/inc/LLGPIO_mux.h new file mode 100644 index 0000000..befc2b8 --- /dev/null +++ b/bsp/projects/microej/gpio/inc/LLGPIO_mux.h @@ -0,0 +1,38 @@ +/** + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LLGPIO_MUX +#define LLGPIO_MUX + +#include "MCXN947_cm33_core0.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_PORT_NUMBER 5 +#define GPIO_BANK_SIZE 32 +#define GPIO00 0 +#define GPIO01 1 +#define GPIO02 2 +#define GPIO03 3 +#define GPIO04 4 +#define GPIO05 5 + +typedef enum gpio_init_status +{ + kSuccess = 0, + kPortError = -1, + kPinError = -2, +}; + +GPIO_Type *GPIO_ARRAY[] = GPIO_BASE_PTRS; + +PORT_Type *PORT_ARRAY[] = PORT_BASE_PTRS; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/bsp/projects/microej/gpio/nxp_gpio.cmake b/bsp/projects/microej/gpio/nxp_gpio.cmake new file mode 100644 index 0000000..ded8786 --- /dev/null +++ b/bsp/projects/microej/gpio/nxp_gpio.cmake @@ -0,0 +1,8 @@ +include_guard() +message("nxp/gpio component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/LLGPIO_impl.c +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) diff --git a/bsp/projects/microej/gpio/src/LLGPIO_impl.c b/bsp/projects/microej/gpio/src/LLGPIO_impl.c new file mode 100644 index 0000000..5b6ab5c --- /dev/null +++ b/bsp/projects/microej/gpio/src/LLGPIO_impl.c @@ -0,0 +1,160 @@ +/** + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * @brief NXP GPIO low level API + * @author Julien Jouan + * @version 1.0.0 + */ + +#include +#include "LLGPIO_mux.h" +#include "sni.h" +#include "fsl_gpio.h" +#include "fsl_port.h" +#include "fsl_clock.h" + +static int8_t check_port_and_pin(uint32_t port, uint32_t pin) +{ + int8_t ret = kPinError; + + switch (port) + { + case GPIO00: + /* According to MCXN947 RM, all pins available on this bank */ + ret = kSuccess; + break; + case GPIO01: + /* According to MCXN947 RM, only pins 0-23 and 30-31 available on this bank */ + if (pin <= 23 || pin >= 30) ret = kSuccess; + break; + case GPIO02: + /* According to MCXN947 RM, only pins 0-11 available on this bank */ + if (pin <= 11) ret = kSuccess; + break; + case GPIO03: + /* According to MCXN947 RM, only pins 0-23 available on this bank */ + if (pin <= 23) ret = kSuccess; + break; + case GPIO04: + /* According to MCXN947 RM, only pins 0-7 and 12-23 available on this bank */ + if (pin <= 7 || (pin >= 12 && pin <= 23)) ret = kSuccess; + break; + case GPIO05: + /* According to MCXN947 RM, only pins 0-9 available on this bank */ + if (pin <= 9) ret = kSuccess; + break; + default: + ret = kPortError; + break; + } + return ret; +} + +int32_t LLGPIO_IMPL_init_gpio_pin(uint32_t pin, uint32_t direction, uint32_t pullConfig) +{ + uint32_t port = pin / GPIO_BANK_SIZE; + pin %= GPIO_BANK_SIZE; + + /* Check that GPIO port and pin used is existing */ + int8_t portPinStatus = check_port_and_pin(port, pin); + if (portPinStatus == kSuccess) + { + CLOCK_EnableClock(CLK_GATE_DEFINE(AHB_CLK_CTRL0, 13 + port)); + CLOCK_EnableClock(CLK_GATE_DEFINE(AHB_CLK_CTRL0, 19 + port)); + + const port_pin_config_t portx_piny_config = {/* Internal pull-up/down resistor is disabled */ + ((pullConfig > 0) ? ((pullConfig == 1) ? kPORT_PullUp : kPORT_PullDown) : kPORT_PullDisable), + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as PIO0_10 */ + kPORT_MuxAlt0, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + + PORT_SetPinConfig(PORT_ARRAY[port], pin, &portx_piny_config); + GPIO_ARRAY[port]->PDDR = ((GPIO_ARRAY[port]->PDDR) & ~(1U << pin)) | (direction << pin); + } + return portPinStatus; +} + +int32_t LLGPIO_IMPL_read_gpio_pin(uint32_t pin) +{ + uint32_t port = pin / GPIO_BANK_SIZE; + pin %= GPIO_BANK_SIZE; + + /* Check that GPIO port and pin used is existing */ + int8_t portPinStatus = check_port_and_pin(port, pin); + int8_t ret; + + if (portPinStatus == kSuccess) + { + ret = GPIO_PinRead(GPIO_ARRAY[port], pin); + } + else + { + ret = portPinStatus; + } + + return ret; +} + +int32_t LLGPIO_IMPL_write_gpio_pin(uint32_t pin, uint32_t level) +{ + uint32_t port = pin / GPIO_BANK_SIZE; + pin %= GPIO_BANK_SIZE; + + /* Check that GPIO port and pin used is existing */ + int8_t portPinStatus = check_port_and_pin(port, pin); + int8_t ret; + + if (portPinStatus == kSuccess) + { + GPIO_PinWrite(GPIO_ARRAY[port], pin, level); + ret = GPIO_PinRead(GPIO_ARRAY[port], pin); + } + else + { + ret = portPinStatus; + } + + return ret; +} + +int32_t LLGPIO_IMPL_toggle_gpio_pin(uint32_t pin) +{ + uint32_t port = pin / GPIO_BANK_SIZE; + pin %= GPIO_BANK_SIZE; + + /* Check that GPIO port and pin used is existing */ + int8_t portPinStatus = check_port_and_pin(port, pin); + int8_t ret; + + if (portPinStatus == kSuccess) + { + GPIO_PortToggle(GPIO_ARRAY[port], (uint32_t) (1 << pin)); + ret = GPIO_PinRead(GPIO_ARRAY[port], pin); + } + else + { + ret = portPinStatus; + } + + return ret; +} diff --git a/bsp/projects/microej/net/inc/LLNET_Common.h b/bsp/projects/microej/net/inc/LLNET_Common.h new file mode 100644 index 0000000..a766ddb --- /dev/null +++ b/bsp/projects/microej/net/inc/LLNET_Common.h @@ -0,0 +1,131 @@ +/* + * C + * + * Copyright 2016-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef LLNET_COMMON_H +#define LLNET_COMMON_H + +/** + * @file + * @brief Common LLNET macro and functions. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#include +#include +#include +#include "LLNET_configuration.h" +#include "async_select.h" + +// Define LLNET_DEBUG in LLNET_configuration.h to enable network debug trace +#ifdef LLNET_DEBUG + #include "fsl_debug_console.h" + #define LLNET_DEBUG_TRACE PRINTF +#else + #define LLNET_DEBUG_TRACE(...) ((void) 0) +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * Sanity check between the expected version of the configuration and the actual version of + * the configuration. + * If an error is raised here, it means that a new version of the CCO has been installed and + * the configuration LLNET_configuration.h must be updated based on the one provided + * by the new CCO version. + */ +#if LLNET_CONFIGURATION_VERSION != 2 + + #error "Version of the configuration file LLNET_configuration.h is not compatible with this implementation." + +#endif + +union llnet_sockaddr{ + struct sockaddr addr; +#if LLNET_AF & LLNET_AF_IPV4 + struct sockaddr_in in; +#endif +#if LLNET_AF & LLNET_AF_IPV6 + struct sockaddr_in6 in6; +#endif +}; + + +int32_t asyncOperation(int32_t fd, SELECT_Operation operation, uint8_t retry); + +/** + * Manages asynchronous I/O operations for NET. + * + */ +int32_t net_asyncOperation(int32_t fd, SELECT_Operation operation, uint8_t retry); + +/** + * @brief Fills-in the given timeval struct with the given time in milliseconds. + * + * @param[in] time_ms time in milliseconds. + * @param[in] time_timeval pointer to the timeval struct to fill-in. + */ +void time_ms_to_timeval(int64_t time_ms, struct timeval* time_timeval); + +/** + * @brief Sets the given socket in non-blocking mode or not. + * + * @param[in] fd socket file descriptor + * @param[in] non_blocking true to enable non-blocking, false to enable blocking. + * + * @return 0 on success, a negative value on error. + */ +int32_t set_socket_non_blocking(int32_t fd, bool non_blocking); + +/** + * @brief Checks if the given socket is in non-blocking mode or not. + * + * @param[in] fd socket file descriptor + * + * @return true if the socket is in non_blocking, false otherwise. + */ +bool is_socket_non_blocking(int32_t fd); + +/** + * @brief Convert a network error code into a java error code. + * + * @param[in] err the error code returned by a BSD-like function. + * + * @return an error code defined in LLNET_ERRORS.h. + */ +int32_t map_to_java_exception(int32_t err); + +#if LLNET_AF & LLNET_AF_IPV6 + +/** + * @brief Determine the scope id for an IP address for IPV6 + * + * @param[in] ip a pointer to a string containing the IP address + * + * @return the scope is for the IP address. Zero if not found + */ +uint32_t getScopeForIp(const char *ip); + +/** + * @brief Map the given IPv4 address into an IPv6 address.

+ * ipv4_addr and ipv6_addr pointers can reference the same memory address. + * + * @param[in] ipv4_addr the IPv4 to map + * @param[out] ipv6_addr the destination IPv6 + */ +void map_ipv4_into_ipv6(in_addr_t* ipv4_addr, struct in6_addr* ipv6_addr); + +#endif + +#ifdef __cplusplus + } +#endif + +#endif // LLNET_COMMON_H diff --git a/bsp/projects/microej/net/inc/LLNET_configuration.h b/bsp/projects/microej/net/inc/LLNET_configuration.h new file mode 100644 index 0000000..cf8a4af --- /dev/null +++ b/bsp/projects/microej/net/inc/LLNET_configuration.h @@ -0,0 +1,172 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief Platform implementation specific macro. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#ifndef LLNET_CONFIGURATION_H +#define LLNET_CONFIGURATION_H + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Compatibility sanity check value. + * This define value is checked in the implementation to validate that the version of this configuration + * is compatible with the implementation. + * + * This value must not be changed by the user of the CCO. + * This value must be incremented by the implementor of the CCO when a configuration define is added, deleted or modified. + */ +#define LLNET_CONFIGURATION_VERSION (2) + +/** + * By default all the llnet_* functions are mapped on the BSD functions. + * Documentation (signature, etc.) for each llnet_* function is available + * in the mapped BSD function documentation. + */ +#define llnet_accept accept +#define llnet_bind bind +#define llnet_close close +#define llnet_connect connect +#define llnet_fcntl fcntl +#define llnet_getpeername getpeername +#define llnet_getsockname getsockname +#define llnet_getsockopt getsockopt +#define llnet_htonl htonl +#define llnet_htons htons +#define llnet_ioctl ioctl +#define llnet_listen listen +#define llnet_ntohs ntohs +#define llnet_recv recv +#define llnet_recvfrom recvfrom +#define llnet_send send +#define llnet_sendto sendto +#define llnet_setsockopt setsockopt +#define llnet_socket socket +#define llnet_shutdown shutdown +#define llnet_gethostname(a, b) (1) + +/** + * Don't modify the LLNET_AF_* constants. + */ +#define LLNET_AF_IPV4 (0x1) +#define LLNET_AF_IPV6 (0x2) +#define LLNET_AF_DUAL ((LLNET_AF_IPV4) | (LLNET_AF_IPV6)) + +/** + * Address family: + * - LLNET_AF_IPV4 for only IPv4 + * - LLNET_AF_IPV6 for only IPv6 + * - LLNET_AF_DUAL for both IPv4 and IPv6 + */ +#define LLNET_AF (LLNET_AF_IPV4) + +/** + * Define the maximum number of sockets that can be handled by the net module + */ +#define LLNET_MAX_SOCKETS MEMP_NUM_NETCONN + +/** + * Returns the errno value for the given file descriptor. + * Given file descriptor may be -1 if no file descriptor is defined. + */ +#include +#define llnet_errno(fd) errno + +/* + * Initialize the network stack. + * Returns 0 on success, -1 on error. + * This method may block and must be called in another RTOS task. + * See async_select task. + * By default this macro does nothing. + */ +#include "lwip_util.h" +#define llnet_init llnet_lwip_init + +/* + * Returns true (bool) if we can call the services of the network stack without jeopardizing the system, + * otherwise returns false (bool). + * Returning true does not mean that a network interface is up. + * By default this macro always return true. + */ +#define llnet_is_ready() (true) + +/** @brief Set this define if the system sends SIGPIPE signal when a connection is closed by the remote host. */ +#if defined(__linux__) || defined(__QNXNTO__) +#define LLNET_IGNORE_SIGPIPE +#endif + + +/** + * Enable network debug trace + */ +//#define LLNET_DEBUG + +/** + * If ioctl() cannot be used to implement the LLNET_STREAMSOCKETCHANNEL_IMPL_available() function, + * define USE_SOCK_OPTION_FOR_AVAILABLE. + */ +//#define USE_SOCK_OPTION_FOR_AVAILABLE + +/** + * If ioctl() cannot be used to implement the LLNET_STREAMSOCKETCHANNEL_IMPL_available() function, + * define USE_MSG_PEEK_FOR_AVAILABLE and NET_EMBEDDED_AVAILABLE_BUFFER_SIZE. + */ +//#define USE_MSG_PEEK_FOR_AVAILABLE +//#define NET_EMBEDDED_AVAILABLE_BUFFER_SIZE (4096) + +/** + * Define USE_IOCTL_FOR_BLOCKING_OPTION to use ioctl() instead of fcntl() to configure socket + * blocking or non-blocking mode. + */ +#define USE_IOCTL_FOR_BLOCKING_OPTION + + +#if LLNET_AF & LLNET_AF_IPV6 +/** + * Only one IPV6 interface is supported + */ +#define LLNET_IPV6_INTERFACE_NAME (char*)"en1" + +#endif + +/** + * Define the mapping between the LLNET provided network interface names + * and the platform dependent network interface names + * - at platform level, the netif names are created by LwIP + * - the loopback netif is always the first one created and maintained forever + * - the station and soft ap netifs can change order, depending on how the application will start/stop them + */ +#if (defined(LWIP_NETIF_LOOPBACK) && (LWIP_NETIF_LOOPBACK != 0)) +#define LLNET_NETIF_NAMES {"loopback_interface", "en1"} +#define PLATFORM_NETIF_NAMES {"lo" , "en" } +/* Number of netifs to store */ +#define NUMB_OF_NETIF_TO_STORE 2 +#else +#define LLNET_NETIF_NAMES {"en1"} +#define PLATFORM_NETIF_NAMES {"en"} +/* Number of netifs to store */ +#define NUMB_OF_NETIF_TO_STORE 1 +#endif + +/*max length of netif name from lwip*/ +#define MAX_SIZE_OF_NETIF_NAME 6 + +#ifdef __cplusplus + } +#endif + +#endif // LLNET_CONFIGURATION_H diff --git a/bsp/projects/microej/net/inc/async_select.h b/bsp/projects/microej/net/inc/async_select.h new file mode 100644 index 0000000..43c251f --- /dev/null +++ b/bsp/projects/microej/net/inc/async_select.h @@ -0,0 +1,77 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef ASYNC_SELECT_H +#define ASYNC_SELECT_H + +/** + * @file + * @brief Asynchronous network select API + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 16 May 2022 + */ + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** @brief Select operations list. */ +typedef enum +{ + SELECT_READ, + SELECT_WRITE +}SELECT_Operation; + +/** + * @brief Execute a select() for the given file descriptor and operation without blocking. + * + * @param[in] fd the file descriptor. + * @param[in] operation the operation (read or write) we want to monitor with the select(). + * + * @return select() result. + */ +int32_t non_blocking_select(int32_t fd, SELECT_Operation operation); + +/** + * @brief Executes asynchronously a select() operation for the given file descriptor. + * This function will suspend the execution of the current Java thread using + * SNI_suspendCurrentJavaThreadWithCallback(). Once the select() succeeds the Java + * thread is resumed and the given SNI callback is called. + * + * @param[in] fd the file descriptor. + * @param[in] operation the operation (read or write) we want to monitor with the select(). + * @param[in] timeout_ms timeout in millisecond + * @param[in] the SNI callback to call when the Java thread is resumed or timeout occurs. + * + * @return 0 on success, -1 on failure. + */ +int32_t async_select(int32_t fd, SELECT_Operation operation, int64_t timeout_ms, SNI_callback callback); + +/** + * @brief Initialize the async_select component. This function must be called prior to any call of + * async_select(). + * + * @return 0 on success, -1 on failure. + */ +int32_t async_select_init(void); + +/** + * @brief Notifies the async_select task that a file descriptor has been closed. + * On some systems the close of a file descriptor does not unblock the select that's + * why we need to notify the async_select task. + */ +void async_select_notify_closed_fd(int32_t fd); + +#ifdef __cplusplus + } +#endif + +#endif // ASYNC_SELECT_H diff --git a/bsp/projects/microej/net/inc/async_select_cache.h b/bsp/projects/microej/net/inc/async_select_cache.h new file mode 100644 index 0000000..077aeaa --- /dev/null +++ b/bsp/projects/microej/net/inc/async_select_cache.h @@ -0,0 +1,77 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief Socket timeout cache API + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 16 May 2022 + */ + +#ifndef ASYNC_SELECT_CACHE_H +#define ASYNC_SELECT_CACHE_H + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Initialize the socket timeout cache + */ +void async_select_init_socket_timeout_cache(void); + +/** + * @brief Get a socket timeout from the cache + * + * @param[in] fd the socket file descriptor + * + * @return socket timeout on success, a negative value on error. + */ +int32_t async_select_get_socket_timeout_from_cache(int32_t fd); + +/** + * @brief Get a socket absolute timeout from the cache (time when the async_select task should unblock the select) + * + * @param[in] fd the socket file descriptor + * + * @return socket absolute timeout on success, a negative value on error. + */ +int64_t async_select_get_socket_absolute_timeout_from_cache(int32_t fd); + +/** + * @brief Set the given socket's timeout in the cache + * + * @param[in] fd the socket file descriptor + * @param[in] timeout socket timeout + */ +void async_select_set_socket_timeout_in_cache(int32_t fd, int32_t timeout); + +/** + * @brief Set the given socket's absolute timeout in the cache (time when the async_select task should unblock the select) + * + * @param[in] fd the socket file descriptor + * @param[in] absolute_timeout socket absolute timeout + * @return 0 on success, -1 on failure. + */ +int32_t async_select_set_socket_absolute_timeout_in_cache(int32_t fd, int64_t absolute_timeout); + +/** + * @brief Remove a socket timeout from the cache + * + * @param[in] fd the socket file descriptor + */ +void async_select_remove_socket_timeout_from_cache(int32_t fd); + +#ifdef __cplusplus + } +#endif + +#endif // ASYNC_SELECT_CACHE_H diff --git a/bsp/projects/microej/net/inc/async_select_configuration.h b/bsp/projects/microej/net/inc/async_select_configuration.h new file mode 100644 index 0000000..79d7254 --- /dev/null +++ b/bsp/projects/microej/net/inc/async_select_configuration.h @@ -0,0 +1,122 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef ASYNC_SELECT_CONFIGURATION_H +#define ASYNC_SELECT_CONFIGURATION_H + +/** + * @file + * @brief Asynchronous network select configuration. + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 16 May 2022 + */ + +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @brief Compatibility sanity check value. + * This define value is checked in the implementation to validate that the version of this configuration + * is compatible with the implementation. + * + * This value must not be changed by the user of the CCO. + * This value must be incremented by the implementor of the CCO when a configuration define is added, deleted or modified. + */ +#define ASYNC_SELECT_CONFIGURATION_VERSION (3) + +/** + * @brief Timeout cache size. + * + * It should be set to the maximum number of sockets (usually defined by LLNET_MAX_SOCKETS) + * or 0 for disabling the timeout cache. + * + * Note: This feature is only needed to manage concurrent accesses to the same socket + * when the socket is configured with a timeout. + */ +#define ASYNC_SELECT_TIMEOUT_CACHE_SIZE LLNET_MAX_SOCKETS + +/** + * @brief Maximum number of asynchronous select that can be done at the same moment. + */ +#define MAX_NB_ASYNC_SELECT (16) + +/** + * @brief async_select task stack size in bytes. + */ +#define ASYNC_SELECT_TASK_STACK_SIZE (2048) + +/** + * @brief async_select task name. + */ +#define ASYNC_SELECT_TASK_NAME ((uint8_t*)"AsyncSelect") + +/** + * @brief async_select task priority. + */ +#define ASYNC_SELECT_TASK_PRIORITY (5) + +/** + * @brief async_select mutex name. + */ +#define ASYNC_SELECT_MUTEX_NAME ((uint8_t*)"AsyncSelectMutex") + +/** + * @brief Timeout in milliseconds used when the async_select task cannot allocate a socket for notifications. + * + * In async_select task a socket is created to notify the task and unlock the select on demand. If this socket cannot + * be created, then the async_select task polls for notification. This constant defines the wait time in milliseconds + * between each poll. + */ +#define ASYNC_SELECT_POLLING_MODE_TIMEOUT_MS (100) + + +/** @brief Set this define if a file descriptor close unblocks the select. */ +#ifndef __linux__ +#define ASYNC_SELECT_CLOSE_UNBLOCK_SELECT +#endif + +/** + * @brief On Linux, a close() operation does not unlock a select(). + * Instead of using a close on notify_fd_cache we will + * use a pipe. + */ +#if defined(__linux__) || defined(__QNXNTO__) +#define ASYNC_SELECT_USE_PIPE_FOR_NOTIFICATION +#endif + +/** + * @brief On some systems, using a NULL pointer as the timeout parameter + * for a select with infinite timeout does not work, so in that case use + * a valid timeout parameter with maximum values as defined by the formula. + * timeout_ms = (int32_t)(timeout->tv_usec/1000 + timeout->tv_sec*1000); + */ +//#define ASYNC_SELECT_USE_MAX_INFINITE_TIMEOUT +//#define ASYNC_SELECT_INFINITE_TIMEOUT_MS (0xFFFFFFFF) +//#define ASYNC_SELECT_MAX_TV_SEC_VALUE (ASYNC_SELECT_INFINITE_TIMEOUT_MS / 1000) +//#define ASYNC_SELECT_MAX_TV_USEC_VALUE ((ASYNC_SELECT_INFINITE_TIMEOUT_MS - ASYNC_SELECT_MAX_TV_SEC_VALUE * 1000) * 1000) + +/** + * @brief The inaddr used to bind the notify socket. + */ +#define ASYNC_SELECT_NOTIFY_SOCKET_BIND_INADDR (INADDR_LOOPBACK) + +/** + * @brief The in6addr used to bind the notify socket. + */ +#define ASYNC_SELECT_NOTIFY_SOCKET_BIND_IN6ADDR (in6addr_loopback) + +#ifdef __cplusplus + } +#endif + +#endif // ASYNC_SELECT_CONFIGURATION_H diff --git a/bsp/projects/microej/net/inc/lwip_util.h b/bsp/projects/microej/net/inc/lwip_util.h new file mode 100644 index 0000000..5c3a935 --- /dev/null +++ b/bsp/projects/microej/net/inc/lwip_util.h @@ -0,0 +1,55 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef __LWIP_UTIL_H +#define __LWIP_UTIL_H + +/** + * @file + * @brief LLNET utility functions for LWIP. + * @author MicroEJ Developer Team + * @version 0.2.2 + * @date 27 November 2020 + */ + +#include +#include + +/** + * Network initialization. Start network interfaces and configure it. + * + * @return 0 if no error occurred, error code otherwise. + */ +int32_t llnet_lwip_init(void); + +/** + * Sets the lwIP network interface name in the stored list. + * + * @param id the id of the network interface to be stored. + * @param netif_name the lwIP network interface name to be stored in the list. + */ +void set_lwip_netif_name(int32_t id, char *netif_name); + +/** + * Gets the lwIP network interface name from the stored list. + * + * @param id the id of the network interface to be stored. + * + * @return the lwIP network interface name from the stored list. + */ +char *get_lwip_netif_name(int32_t id); + +/** + * Gets the lwIP network interface address. + * + * @param name the buffer that store the interface name. + * + * @return the lwIP network interface address or null if no interface with the specified name. + */ +struct netif* getNetworkInterface(int8_t* name); + +#endif // __LWIP_UTIL_H diff --git a/bsp/projects/microej/net/microej_net.cmake b/bsp/projects/microej/net/microej_net.cmake new file mode 100644 index 0000000..539c204 --- /dev/null +++ b/bsp/projects/microej/net/microej_net.cmake @@ -0,0 +1,23 @@ +include_guard() +message("microej/net component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/async_select_cache.c + ${CMAKE_CURRENT_LIST_DIR}/src/async_select.c + ${CMAKE_CURRENT_LIST_DIR}/src/async_select_osal.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_CHANNEL_bsd.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_Common.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_DNS_native_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_DATAGRAMSOCKETCHANNEL_bsd.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_NETWORKADDRESS_bsd.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_SOCKETCHANNEL_bsd.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_NETWORKINTERFACE_lwip.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_STREAMSOCKETCHANNEL_bsd.c + ${CMAKE_CURRENT_LIST_DIR}/src/lwip_util.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_MULTICASTSOCKETCHANNEL_bsd.c +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc/sys) +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc/arpa) +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc/netinet) \ No newline at end of file diff --git a/bsp/projects/microej/net/src/LLNET_CHANNEL_bsd.c b/bsp/projects/microej/net/src/LLNET_CHANNEL_bsd.c new file mode 100644 index 0000000..178dda1 --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_CHANNEL_bsd.c @@ -0,0 +1,538 @@ +/* + * C + * + * Copyright 2014-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + * + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * @brief LLNET_CHANNEL 2.1.0 implementation over BSD-like API. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#include + +#include +#include +#include "LLNET_CONSTANTS.h" +#include "async_select.h" +#include "async_select_cache.h" +#include "LLNET_ERRORS.h" +#include "LLNET_Common.h" +#if LLNET_AF & LLNET_AF_IPV6 +#include +#include +#include +#include +#endif + +#include "LLECOM_NETWORK.h" + +#ifdef LLNET_IGNORE_SIGPIPE +#include +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +int32_t LLNET_CHANNEL_IMPL_close(int32_t fd, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X)\n", __func__, SNI_getCurrentJavaThreadID(), fd); + + (void)retry; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + if(llnet_close(fd) == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + + async_select_remove_socket_timeout_from_cache(fd); + async_select_notify_closed_fd(fd); + + return 0; +} + +int32_t LLNET_CHANNEL_IMPL_initialize(void) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + int32_t res; + + LLECOM_NETWORK_initialize(); + +#ifdef LLNET_IGNORE_SIGPIPE + // Ignore SIGPIPE signal that is sent when a connection is closed by the remote host. + signal(SIGPIPE, SIG_IGN); +#endif + + async_select_init_socket_timeout_cache(); + + res = async_select_init(); + if(res != 0){ + return J_EUNKNOWN; + } + + return 0; + +} + +int32_t LLNET_CHANNEL_IMPL_setBlocking(int32_t fd, uint8_t blocking, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, blocking=%d)\n", __func__, SNI_getCurrentJavaThreadID(), fd, blocking); + + (void)retry; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t res = set_socket_non_blocking(fd, blocking==0 ? true : false); + if(res == 0){ + return 0; + } + return map_to_java_exception(llnet_errno(fd)); +} + +int32_t LLNET_CHANNEL_IMPL_shutdown(int32_t fd, uint8_t retry) +{ + (void)retry; + + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X)\n", __func__, SNI_getCurrentJavaThreadID(), fd); + int32_t ret = llnet_shutdown(fd, SHUT_RD); //shutdown input stream + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X) ret=%d errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, ret, llnet_errno(fd)); + (void)ret; + return 0; +} + +int32_t LLNET_CHANNEL_IMPL_bind(int32_t fd, int8_t* addr, int32_t length, int32_t port, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, port=%d, addrLength=%d,...)\n", __func__, SNI_getCurrentJavaThreadID(), fd, port, length); + + (void)retry; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + union llnet_sockaddr sockaddr = {0}; + int sockaddr_sizeof = 0; + + +#if LLNET_AF == LLNET_AF_IPV4 + if(length == sizeof(in_addr_t)) + { + sockaddr.in.sin_family = AF_INET; + sockaddr.in.sin_port = llnet_htons(port); + sockaddr.in.sin_addr.s_addr = *(in_addr_t*)addr; + sockaddr_sizeof = sizeof(struct sockaddr_in); + } +#endif + +#if LLNET_AF == LLNET_AF_DUAL + if(length == sizeof(in_addr_t) && (uint32_t)SNI_getArrayLength(addr) >= sizeof(struct in6_addr)){ + // Convert IPv4 into IPv6 directly in the addr array + map_ipv4_into_ipv6((in_addr_t*)addr, (struct in6_addr*)addr); + + // Now length of the address in addr is sizeof(struct in6_addr) + length = sizeof(struct in6_addr); + // continue in the following if + } +#endif + +#if LLNET_AF & LLNET_AF_IPV6 + if(length == sizeof(struct in6_addr)) + { + char ipAddress[NI_MAXHOST]; + + sockaddr.in6.sin6_family = AF_INET6; + sockaddr.in6.sin6_port = llnet_htons(port); + // Convert the incoming IP address to ASCII, lookup the interface and set the scope ID + if(inet_ntop(AF_INET6, addr, ipAddress, NI_MAXHOST) != NULL) { + sockaddr.in6.sin6_scope_id=getScopeForIp(ipAddress); + } else { + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, inet_ntop failed, errno=%d, ...)\n", __func__, SNI_getCurrentJavaThreadID(), fd, llnet_errno(fd)); + return J_EINVAL; + } + memcpy(&sockaddr.in6.sin6_addr, addr, sizeof(struct in6_addr)); + sockaddr_sizeof = sizeof(struct sockaddr_in6); + } +#endif + + if(sockaddr_sizeof == 0){ + return J_EINVAL; + } + + int32_t ret = llnet_bind(fd, &sockaddr.addr, sockaddr_sizeof); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, ret=%d, errno=%d, ...)\n", __func__, SNI_getCurrentJavaThreadID(), fd, ret, llnet_errno(fd)); + if(ret == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + return 0; +} + +int32_t LLNET_CHANNEL_IMPL_getOption(int32_t fd, int32_t option, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d)\n", __func__, SNI_getCurrentJavaThreadID(), fd, option); + + (void)retry; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t optname = -1; + int32_t level = SOL_SOCKET; + int32_t optlen = sizeof(int32_t); + int32_t optVal = 0; + struct timeval sock_timeout; + struct linger sock_linger; + void* p_optVal = &optVal; + + if (option == CPNET_SO_TIMEOUT) { + optVal = async_select_get_socket_timeout_from_cache(fd); + if (optVal != -1) { + return optVal; + } + } + + switch (option) { + case CPNET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + case CPNET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + case CPNET_SO_TIMEOUT : + p_optVal = &sock_timeout; + optlen = sizeof(sock_timeout); + optname = SO_RCVTIMEO; + break; + case CPNET_SO_SNDBUF : + optname = SO_SNDBUF; + break; + case CPNET_SO_RCVBUF : + optname = SO_RCVBUF; + break; + case CPNET_TCP_NODELAY: + level = IPPROTO_TCP; + optname = TCP_NODELAY; + break; + case CPNET_IP_TOS: + level = IPPROTO_IP; + optname = IP_TOS; + break; + case CPNET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + case CPNET_IP_MULTICAST_LOOP: +#if LLNET_AF & LLNET_AF_IPV4 + // IPv4 only and dual stack + // In the case of dual stack, it is assumed that IP_MULTICAST_LOOP + // and IPV6_MULTICAST_LOOP always match + level = IPPROTO_IP; + optname = IP_MULTICAST_LOOP; +#else // IPv6 only + level = IPPROTO_IPV6; + optname = IPV6_MULTICAST_LOOP; +#endif + break; + case CPNET_IP_TTL: + level = IPPROTO_IP; + optname = IP_MULTICAST_TTL; + break; + case CPNET_SO_LINGER: + p_optVal = &sock_linger; + optlen = sizeof(sock_linger); + optname = SO_LINGER; + break; + case CPNET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + default: + //option not available + return J_ENOPROTOOPT; + } + + int32_t res = llnet_getsockopt(fd, level, optname, p_optVal, (socklen_t *)&optlen); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d) res=%d errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, option, res, llnet_errno(fd)); + if(res == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + + if (option == CPNET_SO_TIMEOUT) { + async_select_set_socket_timeout_in_cache(fd, (sock_timeout.tv_usec / 1000) + (sock_timeout.tv_sec * 1000)); + } + + if(option == CPNET_SO_TIMEOUT){ + return (sock_timeout.tv_usec / 1000) + (sock_timeout.tv_sec * 1000); + } else if (option == CPNET_SO_LINGER){ + if (sock_linger.l_onoff == 0) { + return -1; + } else { + return sock_linger.l_linger; + } + } + return optVal; +} + +int32_t LLNET_CHANNEL_setOption_multicast_loopback(int32_t fd, int32_t value) +{ + int32_t optname = -1; + int32_t level = SOL_SOCKET; + int32_t res; + int optlen = sizeof(int32_t); + void* p_optval = &value; + +#if LLNET_AF & LLNET_AF_IPV4 + // Set the multicast option for IPv4 + optname = IP_MULTICAST_LOOP; + level = IPPROTO_IP; + res = llnet_setsockopt (fd, level, optname, p_optval, optlen); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, value=%d), res=%d, errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, value, res, llnet_errno(fd)); + if (res == -1) { + return map_to_java_exception(llnet_errno(fd)); + } +#endif +#if LLNET_AF & LLNET_AF_IPV6 + // Set the multicast option for IPv6 + optname = IPV6_MULTICAST_LOOP; + level = IPPROTO_IPV6; + res = llnet_setsockopt (fd, level, optname, p_optval, optlen); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, value=%d), res=%d, errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, value, res, llnet_errno(fd)); + if (res == -1) { + return map_to_java_exception(llnet_errno(fd)); + } +#endif + return 0; +} + +int32_t LLNET_CHANNEL_IMPL_setOption(int32_t fd, int32_t option, int32_t value, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d, value=%d)\n", __func__, SNI_getCurrentJavaThreadID(), fd, option, value); + + (void)retry; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t optname = -1; + int32_t level = SOL_SOCKET; + struct timeval sock_timeout; + struct linger sock_linger; + + int optlen = sizeof(int32_t); + + void* p_optval = &value; + + int sock_type, size; + size = sizeof (int); + + switch (option) { + case CPNET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + case CPNET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + case CPNET_SO_TIMEOUT: + time_ms_to_timeval(value, &sock_timeout); + p_optval = &sock_timeout; + optlen = sizeof(sock_timeout); + optname = SO_RCVTIMEO; + break; + case CPNET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + case CPNET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + case CPNET_TCP_NODELAY: + level = IPPROTO_TCP; + optname = TCP_NODELAY; + break; + case CPNET_IP_TOS: + level = IPPROTO_IP; + optname = IP_TOS; + break; + case CPNET_SO_REUSEADDR : + optname = SO_REUSEADDR; + break; + case CPNET_IP_MULTICAST_LOOP: + return LLNET_CHANNEL_setOption_multicast_loopback(fd, value); + case CPNET_IP_TTL: + level = IPPROTO_IP; + optname = IP_MULTICAST_TTL; + break; + case CPNET_SO_LINGER: + if (value == -1) { + sock_linger.l_onoff = 0; + sock_linger.l_linger = 0; + } else if (value >= 0) { + sock_linger.l_onoff = 1; + sock_linger.l_linger = value; + } + p_optval = &sock_linger; + optlen = sizeof(sock_linger); + optname = SO_LINGER; + break; + case CPNET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + default: + /* option not available */ + return J_ENOPROTOOPT; + } + int32_t res = llnet_setsockopt (fd, level, optname, p_optval, optlen); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d, value=%d), res=%d, errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, option, value, res, llnet_errno(fd)); + if (res == -1) { + return map_to_java_exception(llnet_errno(fd)); + } + + if (option == CPNET_SO_TIMEOUT) { + async_select_set_socket_timeout_in_cache(fd, value); + } else if(option == CPNET_SO_REUSEADDR){ + llnet_getsockopt(fd, level, SO_TYPE, (char *)&sock_type, (socklen_t *)&size); + if(sock_type == SOCK_DGRAM){ + // Force enable/disable SO_REUSEPORT on UDP/Multicast sockets + // to allow multiple multicast sockets to be bound to the same address + llnet_setsockopt (fd, level, SO_REUSEPORT, p_optval, optlen); + } + } + return 0; +} + +int32_t LLNET_CHANNEL_IMPL_getOptionAsByteArray(int32_t fd, int32_t option, int8_t* dst, int32_t dstLength, uint8_t retry) +{ + /* Remove unused parameters warning*/ + (void)fd; + (void)dst; + (void)dstLength; + (void)retry; + + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d, dstLength=%d)\n", __func__, SNI_getCurrentJavaThreadID(), fd, option, dstLength); + + switch (option) { + case CPNET_IP_MULTICAST_IF: + case CPNET_IP_MULTICAST_IF2: + { +#if LLNET_AF & LLNET_AF_IPV4 + // Option valid only for IPv4 + if((uint32_t)dstLength >= sizeof(struct in_addr)){ + + socklen_t option_length = sizeof(struct in_addr); + + int32_t res = llnet_getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, dst, &option_length); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d) res=%d errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, option, res, llnet_errno(fd)); + if(res == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + + return option_length; + } + else { + return J_EINVAL; + } +#else //Only IPv6 + // Not managed + return J_ENOPROTOOPT; +#endif + } + default: + //option not available + return J_ENOPROTOOPT; + } +} + +int32_t LLNET_CHANNEL_IMPL_setOptionAsByteArray(int32_t fd, int32_t option, int8_t* value, int32_t valueLength, uint8_t retry) +{ + /* remove unused retry parameter warning*/ + (void)(retry); + + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d, valueLength=%d)\n", __func__, SNI_getCurrentJavaThreadID(), fd, option, valueLength); + + switch (option) { + case CPNET_IP_MULTICAST_IF: + case CPNET_IP_MULTICAST_IF2: + { +#if LLNET_AF & LLNET_AF_IPV4 + // Option valid only for IPv4 + if(valueLength == sizeof(struct in_addr)){ + int32_t res; + res = llnet_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, value, sizeof(struct in_addr)); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d) res=%d errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, option, res, llnet_errno(fd)); + if(res == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + return 0; + } +#endif +#if LLNET_AF & LLNET_AF_IPV6 + //Only IPv6 + if(valueLength == sizeof(struct in6_addr)) { + // get interface name + struct ifaddrs * ifaddrs = NULL; + struct ifaddrs * i; + if(getifaddrs(&ifaddrs) != 0) { + return J_EUNKNOWN; + } + uint32_t ifindex; + // Walk the interface address structure until we match the interface address + for (i = ifaddrs; i != NULL; i = i->ifa_next) { + if (AF_INET6 == i->ifa_addr->sa_family) { + if(memcmp(value, ((struct sockaddr_in6*)i->ifa_addr)->sin6_addr.s6_addr, valueLength) == 0) { + ifindex = if_nametoindex(i->ifa_name); + break; + } + } + } + freeifaddrs(ifaddrs); + + int32_t res; + res = llnet_setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, option=%d) res=%d errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, option, res, llnet_errno(fd)); + if(res == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + return 0; + } +#endif + return J_EINVAL; + } + default: + /* option not available */ + return J_ENOPROTOOPT; + } +} + +int32_t LLNET_CHANNEL_IMPL_listen(int32_t fd, int32_t backlog, uint8_t retry) +{ + /* remove unused retry parameter warning*/ + (void)(retry); + + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, backlog=%d)\n", __func__, SNI_getCurrentJavaThreadID(), fd, backlog); + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t res = llnet_listen(fd, backlog); + if(res == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + return 0; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/LLNET_Common.c b/bsp/projects/microej/net/src/LLNET_Common.c new file mode 100644 index 0000000..038ec38 --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_Common.c @@ -0,0 +1,299 @@ +/* + * C + * + * Copyright 2016-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_Common implementation over BSD-like API. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#include "LLNET_Common.h" +#include "async_select.h" +#include "async_select_cache.h" +#include +#include "LLNET_CHANNEL_impl.h" +#include "LLNET_CONSTANTS.h" +#include "LLNET_ERRORS.h" +#include +#if LLNET_AF & LLNET_AF_IPV6 +#include +#include +#include +#include +#endif + +#ifndef USE_IOCTL_FOR_BLOCKING_OPTION +#include +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* @brief external function used to retrieve currentTime (same as MicroJvm) */ +extern int64_t LLMJVM_IMPL_getCurrentTime__Z(uint8_t system); + +/* + * @brief perform an asynchronous operation. + * The operation timeout is checked from the timeout cache before performing the real action. + * + * @return 0 on success, J_ETIMEDOUT if the operation timed out or -1 if the async select queue is full. + */ +int32_t asyncOperation(int32_t fd, SELECT_Operation operation, uint8_t retry){ + int32_t timeout; + + // the socket is not readable or writable. + // A blocking request is added in the dispatch event queue. + timeout = async_select_get_socket_timeout_from_cache(fd); + if (timeout == -1) { + timeout = LLNET_CHANNEL_IMPL_getOption(fd, CPNET_SO_TIMEOUT, 0); + } + + //check the timeout + if(timeout < 0){ + //error code + return timeout; + } + if((timeout != 0) && retry){ + int64_t absolute_timeout = async_select_get_socket_absolute_timeout_from_cache(fd); + + //The socket has been configured with a timeout + //AND there is no available data + //AND this is the second read (retry==true) + //THEN most likely the timeout has been reached during the first read + //BUT there is a special case where more Java threads were waiting for a notification + //on the same socket, and more Java threads were woken up by the async_select, but the + //first Java thread which ran consumed the socket event, so we can end up in this case + //without the full timeout being passed + //SO check that the timeout really passed for the socket, otherwise add a new async_select + //request with the remaining timeout + if (absolute_timeout != -1) { + int64_t current_time = LLMJVM_IMPL_getCurrentTime__Z(1); + if (current_time >= absolute_timeout) { + return J_ETIMEDOUT; + } else { + timeout = absolute_timeout - current_time; + } + } else { + return J_ETIMEDOUT; + } + } + + return async_select(fd, operation, timeout, NULL); +} + + +int32_t net_asyncOperation(int32_t fd, SELECT_Operation operation, uint8_t retry){ + + int32_t res = asyncOperation(fd, operation, retry); + if(res == 0){ + // request added in the queue + return J_NET_NATIVE_CODE_BLOCKED_WITHOUT_RESULT; + } + if(res == -1){ + // requests queue limit reached + return J_ASYNC_BLOCKING_REQUEST_QUEUE_LIMIT_REACHED; + } + // other net error is directly returned + return res; +} + +/** + * @brief Fills-in the given timeval struct with the given time in milliseconds. + * + * @param[in] time_ms time in milliseconds. + * @param[in] time_timeval pointer to the timeval struct to fill-in. + */ +void time_ms_to_timeval(int64_t time_ms, struct timeval* time_timeval){ + if(time_ms >= 1000){ + time_timeval->tv_sec = time_ms / 1000; + time_timeval->tv_usec = (time_ms % 1000) * 1000; + }else{ + time_timeval->tv_sec = 0; + time_timeval->tv_usec = time_ms * 1000; + } +} + + +/** + * @brief Sets the given socket in non-blocking mode or not. + * + * @param[in] fd socket file descriptor + * @param[in] non_blocking true to enable non-blocking, false to enable blocking. + * + * @return 0 on success, a negative value on error. + */ +int32_t set_socket_non_blocking(int32_t fd, bool non_blocking){ +#ifdef USE_IOCTL_FOR_BLOCKING_OPTION + int32_t non_blocking_option = non_blocking==true ? 1 : 0; + int32_t res = llnet_ioctl(fd, FIONBIO, &non_blocking_option); + + return res; +#else + int32_t flags = llnet_fcntl(fd, F_GETFL, 0); + if(flags == -1){ + return -1; + } + + if(non_blocking == true){ + flags |= O_NONBLOCK; + } + else { + flags &= ~O_NONBLOCK; + } + return llnet_fcntl(fd, F_SETFL, flags); +#endif +} + +/** + * @brief Checks if the given socket is in non-blocking mode or not. + * + * @param[in] fd socket file descriptor + * + * @return true if the socket is non blocking, false if the socket is blocking or an error occurs. + */ +bool is_socket_non_blocking(int32_t fd){ +#ifdef USE_IOCTL_FOR_BLOCKING_OPTION + (void)fd; + + return false; +#else + int32_t flags = llnet_fcntl(fd, F_GETFL, 0); + if(flags == -1){ + return false; + } + + return (flags & O_NONBLOCK) != 0; +#endif +} + +/** + * @brief Convert a network error code into a java error code. + * + * @param[in] err the error code returned by a BSD-like function. + * + * @return an error code defined in LLNET_ERRORS.h. + */ +int32_t map_to_java_exception(int32_t err){ + switch(err){ + case (EACCES): + return J_EACCES; + case (EBADF): + return J_EBADF; + case (EHOSTDOWN): + return J_EHOSTDOWN; + case (ENETDOWN): + return J_ENETDOWN; + case (ENETUNREACH): + return J_ENETUNREACH; + case (EADDRINUSE): + return J_EADDRINUSE; + case (EINVAL): + return J_EINVAL; + case (ECONNABORTED): + return J_ECONNABORTED; + case (ENOPROTOOPT): + return J_ENOPROTOOPT; + case (ENOTCONN): + return J_ENOTCONN; + case (EAFNOSUPPORT): + return J_EAFNOSUPPORT; + case (ECONNREFUSED): + return J_ECONNREFUSED; + case (EISCONN): + return J_EISCONN; + case (ECONNRESET): + return J_ECONNRESET; + case (EMSGSIZE): + return J_EMSGSIZE; + case (EPIPE): + return J_EPIPE; + case (ETIMEDOUT): + return J_ETIMEDOUT; + case (ENOBUFS): + case (ENOSPC): + case (ENOMEM): + return J_ENOMEM; + case (EHOSTUNREACH): + return J_EHOSTUNREACH; + default: + return J_EUNKNOWN; + } +} + +#if LLNET_AF & LLNET_AF_IPV6 + +uint32_t getScopeForIp(const char *ip){ + struct ifaddrs *addrs = NULL; + char ipAddress[NI_MAXHOST]; + uint32_t scope = 0; + + // walk over the list of all interface addresses + getifaddrs(&addrs); + for (struct ifaddrs *addr = addrs; addr; addr = addr->ifa_next) { + if (addr->ifa_addr && addr->ifa_addr->sa_family == AF_INET6) { // only interested in ipv6 ones + getnameinfo(addr->ifa_addr, sizeof(struct sockaddr_in6), ipAddress, + sizeof(ipAddress), NULL, 0, NI_NUMERICHOST); + // result actually contains the interface name, so strip it + for (int i = 0; ipAddress[i]; i++) { + if (ipAddress[i] == '%') { + ipAddress[i] = '\0'; + break; + } + } + // if the ip matches, convert the interface name to a scope index + if (strcmp(ipAddress, ip) == 0) { + scope = if_nametoindex(addr->ifa_name); + break; + } + } + } + // If the scope wasn't set in the name search, set it to LLNET_IPV6_INTERFACE_NAME + if(0 == scope) { + scope = if_nametoindex(LLNET_IPV6_INTERFACE_NAME); + } + freeifaddrs(addrs); + return scope; +} + +/** + * @brief Map the given IPv4 address into an IPv6 address.

+ * ipv4_addr and ipv6_addr pointers can reference the same memory address. + * + * @param[in] ipv4_addr the IPv4 to map + * @param[out] ipv6_addr the destination IPv6 + */ +void map_ipv4_into_ipv6(in_addr_t* ipv4_addr, struct in6_addr* ipv6_addr){ + // Convert IPv4 into IPv6 directly in the addr array + + if(*(ipv4_addr) == llnet_htonl(INADDR_ANY)){ + // Use IPv6 wildcard address + *ipv6_addr = in6addr_any; + } + else { + uint8_t* ipv6_addr_u8 = (uint8_t*)ipv6_addr; + // Destination offset of the IPv4 address: end of struct in6_addr + int ipv4_dest_offset = sizeof(struct in6_addr) - sizeof(in_addr_t); + // Copy the IPv4 address at the end of struct in6_addr + memcpy(ipv6_addr_u8 + ipv4_dest_offset, ipv4_addr, sizeof(in_addr_t)); + + // Add 0xFF:0xFF before + ipv6_addr_u8[ipv4_dest_offset - 1] = 0xFF; + ipv6_addr_u8[ipv4_dest_offset - 2] = 0xFF; + + // Set to 0 all the other bytes + memset(ipv6_addr_u8, 0, ipv4_dest_offset - 2); + } +} + +#endif + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/LLNET_DATAGRAMSOCKETCHANNEL_bsd.c b/bsp/projects/microej/net/src/LLNET_DATAGRAMSOCKETCHANNEL_bsd.c new file mode 100644 index 0000000..dc5fb0d --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_DATAGRAMSOCKETCHANNEL_bsd.c @@ -0,0 +1,216 @@ +/* + * C + * + * Copyright 2014-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_DATAGRAMSOCKETCHANNEL 2.1.0 implementation over BSD-like API. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#include + +#include +#include +#include "LLNET_CONSTANTS.h" +#include "LLNET_ERRORS.h" +#include "LLNET_Common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +int64_t DatagramSocketChannel_recvfrom(int32_t fd, int8_t* dst, int32_t dstOffset, int32_t dstLength, int8_t* hostPort, int32_t hostPortLength, uint8_t retry){ + LLNET_DEBUG_TRACE("%s(fd=0x%X, dstLength=%d, hostPortLength=%d, retry=%d)\n", __func__, fd, dstLength, hostPortLength, retry); + + (void)retry; + + union llnet_sockaddr sockaddr = {0}; + int32_t addrLen = sizeof(sockaddr); + int32_t flags = MSG_WAITALL; + int32_t ret = llnet_recvfrom(fd, dst+dstOffset, dstLength, flags, &sockaddr.addr, (socklen_t *)&addrLen); + + LLNET_DEBUG_TRACE("%s recvfrom() returned %d errno = %d\n",__func__,ret,llnet_errno(fd)); + if (ret == -1) { + LLNET_DEBUG_TRACE("%s returning %d\n", __func__, map_to_java_exception(llnet_errno(fd))); + return map_to_java_exception(llnet_errno(fd)); + } +#if LLNET_AF & LLNET_AF_IPV4 + if (sockaddr.addr.sa_family == AF_INET) { + if((uint32_t)hostPortLength < (sizeof(in_addr_t) + sizeof(int32_t))){ + return J_EINVAL; + } + // push host address in result buffer + *((in_addr_t*)hostPort) = sockaddr.in.sin_addr.s_addr; + hostPort += sizeof(in_addr_t); + // push host port in result buffer + *((int32_t*)hostPort) = llnet_ntohs(sockaddr.in.sin_port); + // add data receive length in return value + int64_t retValue = (((int64_t)ret) << 32l); + // add host length in return value + retValue |= sizeof(in_addr_t); + LLNET_DEBUG_TRACE("%s returning %llx\n", __func__, retValue); + return retValue; + } +#endif +#if LLNET_AF & LLNET_AF_IPV6 + if (sockaddr.addr.sa_family == AF_INET6) { + if((uint32_t)hostPortLength < (sizeof(struct in6_addr)+sizeof(int32_t))){ + LLNET_DEBUG_TRACE("%s returning J_EINVAL hostPortLength = %d\n", __func__,hostPortLength); + return J_EINVAL; + } + // push host address in result buffer + memcpy(hostPort, (void*)&sockaddr.in6.sin6_addr, sizeof(struct in6_addr)); + // push host port in result buffer + hostPort += sizeof(struct in6_addr); + *((int32_t*)hostPort) = llnet_ntohs(sockaddr.in6.sin6_port); + LLNET_DEBUG_TRACE("%s sockaddr.in6.sin6_port = 0x%x\n", __func__, sockaddr.in6.sin6_port); + LLNET_DEBUG_TRACE("%s llnet_ntohs(sockaddr.in6.sin6_port) = 0x%x\n", __func__, llnet_ntohs(sockaddr.in6.sin6_port)); + // add data receive length in return value + int64_t retValue = (((int64_t)ret) << 32l); + // add host length in return value + retValue |= (sizeof(struct in6_addr)); + LLNET_DEBUG_TRACE("%s returning %llx\n", __func__, retValue); + return retValue; + } +#endif + + //unsupported address family + return J_EAFNOSUPPORT; +} + +int32_t DatagramSocketChannel_sendto(int32_t fd, int8_t* src, int32_t srcoffset, int32_t srclength, int8_t* addr, int32_t addrlength, int32_t port, uint8_t retry){ + LLNET_DEBUG_TRACE("%s(fd=0x%X, ..., retry=%d)\n", __func__, fd, retry); + union llnet_sockaddr sockaddr = {0}; + int sockaddr_sizeof = 0; + + (void)retry; + +#if LLNET_AF == LLNET_AF_IPV4 + if(addrlength == sizeof(in_addr_t)) + { + sockaddr.in.sin_family = AF_INET; + sockaddr.in.sin_addr.s_addr = *((in_addr_t*)addr); + sockaddr.in.sin_port = llnet_htons(port); + sockaddr_sizeof = sizeof(struct sockaddr_in); + } +#endif + +#if LLNET_AF == LLNET_AF_DUAL + if(addrlength == sizeof(in_addr_t) && (uint32_t)SNI_getArrayLength(addr) >= sizeof(struct in6_addr)){ + // Convert IPv4 into IPv6 directly in the addr array + map_ipv4_into_ipv6((in_addr_t*)addr, (struct in6_addr*)addr); + + // Now length of the address in addr is sizeof(struct in6_addr) + addrlength = sizeof(struct in6_addr); + // continue in the following if + } +#endif + +#if LLNET_AF & LLNET_AF_IPV6 + if(addrlength == sizeof(struct in6_addr)) + { + sockaddr.in6.sin6_family = AF_INET6; + memcpy((void*)&sockaddr.in6.sin6_addr, addr, sizeof(struct in6_addr)); + sockaddr.in6.sin6_port = llnet_htons(port); + sockaddr_sizeof = sizeof(struct sockaddr_in6); + } +#endif + if(sockaddr_sizeof == 0){ + LLNET_DEBUG_TRACE("%s(fd=0x%X) invalid address type addrlength=%d\n", __func__, fd, addrlength); + return J_EINVAL; + } + int32_t flags = 0; + LLNET_DEBUG_TRACE("%s(fd=0x%X) calling sendto AddrSize: %d\n", __func__, fd, sockaddr_sizeof); + + int32_t ret = llnet_sendto(fd, src+srcoffset, srclength, flags,&sockaddr.addr, sockaddr_sizeof); + + LLNET_DEBUG_TRACE("%s(fd=0x%X) sendto result=%d errno=%d\n", __func__, fd, ret, llnet_errno(fd)); + + if(ret == -1 && llnet_errno(fd) == EISCONN){ + //The datagram socket is connected. + //According to BSD sendto specification, EISCONN can be set when trying to send a packet + //on a connected stream or datagram socket if destination address is not null. + //Retry to send the packet without specifying the destination address (set it to null). + ret = llnet_sendto(fd, src+srcoffset, srclength, flags,(struct sockaddr*)NULL, 0); + } + if(ret == -1 && (llnet_errno(fd) == EAGAIN || llnet_errno(fd) == EWOULDBLOCK)){ + ret = 0; + } + if(ret == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + + return ret; +} + +int64_t LLNET_DATAGRAMSOCKETCHANNEL_IMPL_receive(int32_t fd, int8_t* dst, int32_t dstOffset, int32_t dstLength, int8_t* hostPort, int32_t hostPortLength, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s(fd=0x%X, ..., retry=%d hostPortLength = %d)\n", __func__, fd, retry, hostPortLength); + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + // first, a select with zero timeout is done to check if the socket is readable or writable. + // The select call is non blocking when the given timeout is equals to zero. + // On success, the socket is ready to read or write data. A blocking call to recv function + // can be done. It will not block the socket. + int32_t selectRes = non_blocking_select(fd, SELECT_READ); + + if(selectRes == 0){ + return net_asyncOperation(fd, SELECT_READ, retry); + }else{ + return DatagramSocketChannel_recvfrom(fd, dst, dstOffset, dstLength, hostPort, hostPortLength, retry); + } + +} + +int32_t LLNET_DATAGRAMSOCKETCHANNEL_IMPL_send(int32_t fd, int8_t* src, int32_t srcoffset, int32_t srclength, int8_t* addr, int32_t addrlength, int32_t port, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s(fd=0x%X, ..., retry=%d addrlength = %d)\n", __func__, fd, retry, addrlength); + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + // first, a select with zero timeout is done to check if the socket is readable or writable. + // The select call is non blocking when the given timeout is equals to zero. + // On success, the socket is ready to read or write data. A blocking call to recv function + // can be done. It will not block the socket. + int32_t selectRes = non_blocking_select(fd, SELECT_WRITE); + + if(selectRes == 0){ + return net_asyncOperation(fd, SELECT_WRITE, retry); + }else{ + return DatagramSocketChannel_sendto(fd, src, srcoffset, srclength, addr, addrlength, port, retry); + } + +} + +int32_t LLNET_DATAGRAMSOCKETCHANNEL_IMPL_disconnect(int32_t fd, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s(fd=0x%X)\n ", __func__, fd); + + (void)retry; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + struct sockaddr sockaddr = {0}; + sockaddr.sa_family = AF_UNSPEC; + if(llnet_connect(fd, &sockaddr, sizeof(struct sockaddr)) == -1) { + return map_to_java_exception(llnet_errno(fd)); + } + return 0; //success +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/LLNET_DNS_native_impl.c b/bsp/projects/microej/net/src/LLNET_DNS_native_impl.c new file mode 100644 index 0000000..71aea75 --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_DNS_native_impl.c @@ -0,0 +1,73 @@ +/* + * C + * + * Copyright 2014-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_DNS native implementation over LWIP. + * @author MicroEJ Developer Team + * @version 0.1.3 + * @date 27 November 2020 + */ +#include + +#include +#include +#include +#include "LLNET_CONSTANTS.h" +#include "LLNET_ERRORS.h" +#include "LLNET_Common.h" + +int32_t LLNET_DNS_IMPL_getHostByAddr(int8_t* inOut, int32_t offset, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + // FIXME no function to retrieve host name associated to an ip address + return J_EHOSTUNKNOWN; +} + +int32_t LLNET_DNS_IMPL_getHostByNameAt(int32_t index, int8_t* inOut, int32_t offset, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + struct hostent *hret; + hret = gethostbyname((char const *)inOut); + + if (hret == NULL){ + return J_EHOSTUNKNOWN; + } + if(hret->h_addrtype == AF_INET){ + int32_t addrLength = 4; + // we wants the index-th address in the address list + int8_t* addr = (int8_t*)(hret->h_addr_list[index]); + if(addr != NULL){ + memcpy(inOut+offset, addr, addrLength); + return addrLength; + } + + } + return J_EHOSTUNKNOWN; +} + +int32_t LLNET_DNS_IMPL_getHostByNameCount(int8_t* hostname, int32_t offset, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + struct hostent * hret; + hret = gethostbyname((char const *)hostname); + if (hret == NULL){ + return J_EHOSTUNKNOWN; + } + + int32_t counter = 0; + int8_t** h_addr_list = (int8_t**)(hret->h_addr_list); + // h_addr_list is null terminated by construction + // (see struct hostent description in man 3 gethostbyname) + // while the next pointer isn't this null pointer, we have at least + // one address more to read + while (h_addr_list[counter] != NULL) { + ++counter; + } + LLNET_DEBUG_TRACE("%s host count = %d\n", __func__,counter); + return counter; +} diff --git a/bsp/projects/microej/net/src/LLNET_MULTICASTSOCKETCHANNEL_bsd.c b/bsp/projects/microej/net/src/LLNET_MULTICASTSOCKETCHANNEL_bsd.c new file mode 100644 index 0000000..624bf03 --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_MULTICASTSOCKETCHANNEL_bsd.c @@ -0,0 +1,115 @@ +/* + * C + * + * Copyright 2014-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_MULTICASTSOCKETCHANNEL 2.1.0 implementation over BSD-like API. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#include + +#include +#include +#include "LLNET_CONSTANTS.h" +#include "LLNET_ERRORS.h" +#include "LLNET_Common.h" +#include "LLNET_CHANNEL_impl.h" +#if LLNET_AF & LLNET_AF_IPV6 +#include +#include +#include +#include +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +int32_t LLNET_MULTICASTSOCKETCHANNEL_IMPL_getTimeToLive(int32_t fd, uint8_t retry) +{ + (void)retry; + + LLNET_DEBUG_TRACE("%s(fd=0x%X, ..., retry=%d)\n", __func__, fd, retry); + return LLNET_CHANNEL_IMPL_getOption(fd, CPNET_IP_TTL, 0); +} + +int32_t LLNET_MULTICASTSOCKETCHANNEL_IMPL_setTimeToLive(int32_t fd, int32_t ttl, uint8_t retry) +{ + (void)retry; + + LLNET_DEBUG_TRACE("%s(fd=0x%X, ..., retry=%d)\n", __func__, fd, retry); + return LLNET_CHANNEL_IMPL_setOption(fd, CPNET_IP_TTL, ttl, 0); +} + +int32_t LLNET_MULTICASTSOCKETCHANNEL_IMPL_joinOrLeave(int32_t fd, uint8_t join, int8_t* mcastAddr, int32_t mcastAddrLength, int8_t* netIfAddr, int32_t netIfAddrLength, uint8_t retry) +{ + (void)retry; + + LLNET_DEBUG_TRACE("%s(fd=0x%X, join=%d, ..., retry=%d, mcastAddrLength=%d, netIfAddrLength=%d)\n", __func__, fd, join, retry, mcastAddrLength, netIfAddrLength); +#if LLNET_AF & LLNET_AF_IPV4 + + if(mcastAddrLength==sizeof(in_addr_t) && (netIfAddrLength==sizeof(in_addr_t) || netIfAddrLength==0)) + { + struct ip_mreq optval; + optval.imr_multiaddr.s_addr = *(in_addr_t*)mcastAddr; + if(netIfAddrLength != 0){ + optval.imr_interface.s_addr = *(in_addr_t*)netIfAddr; + } + else { + // No interface specified, use INADDR_ANY + optval.imr_interface.s_addr = llnet_htonl(INADDR_ANY); + } + if (llnet_setsockopt(fd, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &optval, sizeof(optval)) == -1) + { + LLNET_DEBUG_TRACE("%s(%d): errno=%d\n", __func__, __LINE__, llnet_errno(fd)); + return map_to_java_exception(llnet_errno(fd)); + } + return 0; + } +#endif +#if LLNET_AF & LLNET_AF_IPV6 + if(mcastAddrLength==sizeof(struct in6_addr) && (netIfAddrLength==sizeof(struct in6_addr) || netIfAddrLength==0)) + { + struct ipv6_mreq optval; + memcpy(optval.ipv6mr_multiaddr.s6_addr, mcastAddr, sizeof(struct in6_addr)); + if(netIfAddrLength != 0){ + // get interface name + struct ifaddrs * ifaddrs = NULL; + struct ifaddrs * i; + if(getifaddrs(&ifaddrs) != 0) { + return J_EUNKNOWN; + } + // Walk the interface address structure until we match the interface address + for (i = ifaddrs; i != NULL; i = i->ifa_next) { + if (AF_INET6 == i->ifa_addr->sa_family) { + if(memcmp(netIfAddr, ((struct sockaddr_in6*)i->ifa_addr)->sin6_addr.s6_addr, netIfAddrLength) == 0) { + optval.ipv6mr_interface = if_nametoindex(i->ifa_name); + break; + } + } + } + freeifaddrs(ifaddrs); + } + else { + optval.ipv6mr_interface = 0; + } + if (llnet_setsockopt(fd, IPPROTO_IPV6, join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, &optval, sizeof(optval)) == -1) + { + LLNET_DEBUG_TRACE("%s(%d): errno=%d\n", __func__, __LINE__, llnet_errno(fd)); + return map_to_java_exception(llnet_errno(fd)); + } + return 0; + } +#endif + return J_EINVAL; +} +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/LLNET_NETWORKADDRESS_bsd.c b/bsp/projects/microej/net/src/LLNET_NETWORKADDRESS_bsd.c new file mode 100644 index 0000000..6041c71 --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_NETWORKADDRESS_bsd.c @@ -0,0 +1,106 @@ +/* + * C + * + * Copyright 2014-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_NETWORKADDRESS 2.1.0 implementation over BSD-like API. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#include + +#include +#include +#include "LLNET_CONSTANTS.h" +#include "LLNET_ERRORS.h" +#include "LLNET_Common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#define LOCALHOST_NAME ("localhost") + +int32_t LLNET_NETWORKADDRESS_IMPL_getLocalHostnameNative(int8_t* result, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + + (void)retry; + + jint ret; + ret = llnet_gethostname(result, length); + + if(ret == 0){ + // From gethostname() man: + // * If the null-terminated hostname is too large to fit, then the name is truncated, and no error + // * is returned (but see NOTES below). POSIX.1-2001 says that if such + // * truncation occurs, then it is unspecified whether the returned buffer + // * includes a terminating null byte. + // + // To avoid any issue, we set to 0 the last char. + result[length-1] = 0; + }else{ + strncpy((char*)result, LOCALHOST_NAME, length); + + // From strncpy() man: + // * Warning: If there is no null byte among the first n bytes + // * of src, the string placed in dest will not be null terminated. + // + // To avoid any issue, we set to 0 the last char. + result[length-1] = 0; + } + return 0; +} + +int32_t LLNET_NETWORKADDRESS_IMPL_lookupInaddrAny(int8_t* result, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + + (void)retry; + +// If IPv6 or IPv4+IPv6 configuration, then use IPv6. Otherwise (only IPv4 configuration) use IPv4. +#if LLNET_AF & LLNET_AF_IPV6 + if((uint32_t)length >= sizeof(struct in6_addr)){ + *((struct in6_addr*)result) = in6addr_any; + return sizeof(struct in6_addr); + } +#else // only IPv4 + if((uint32_t)length >= sizeof(struct in_addr)){ + *((in_addr_t*)result) = llnet_htonl(INADDR_ANY); + return sizeof(in_addr_t); + } +#endif + + return J_EINVAL; +} + +int32_t LLNET_NETWORKADDRESS_IMPL_loopbackAddress(int8_t* result, int32_t length, uint8_t retry){ + LLNET_DEBUG_TRACE("%s\n", __func__); + + (void)retry; + +// If IPv6 or IPv4+IPv6 configuration, then use IPv6. Otherwise (only IPv4 configuration) use IPv4. +#if LLNET_AF & LLNET_AF_IPV6 + if((uint32_t)length >= sizeof(struct in6_addr)){ + *((struct in6_addr*)result) = in6addr_loopback; + return sizeof(struct in6_addr); + } +#else // only IPv4 + if((uint32_t)length >= sizeof(struct in_addr)){ + *((in_addr_t*)result) = llnet_htonl(INADDR_LOOPBACK); + return sizeof(in_addr_t); + } +#endif + + return J_EINVAL; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/LLNET_NETWORKINTERFACE_lwip.c b/bsp/projects/microej/net/src/LLNET_NETWORKINTERFACE_lwip.c new file mode 100644 index 0000000..db791ce --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_NETWORKINTERFACE_lwip.c @@ -0,0 +1,229 @@ +/* + * C + * + * Copyright 2014-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_NETWORKINTERFACE 2.1.0 implementation over LWIP. + * @author MicroEJ Developer Team + * @version 0.2.2 + * @date 27 November 2020 + */ + +#include + +#include +#include +#include +#include +#include +#include "LLNET_CONSTANTS.h" +#include "LLNET_ERRORS.h" +#include "LLNET_Common.h" +#include "lwip_util.h" + +#ifdef __cplusplus + extern "C" { +#endif + +int32_t LLNET_NETWORKINTERFACE_IMPL_getVMInterface(int32_t id, int8_t* nameReturned, int32_t length, uint8_t retry) +{ + char *llnet_netif[] = LLNET_NETIF_NAMES; + char *platform_netif[] = PLATFORM_NETIF_NAMES; + + LLNET_DEBUG_TRACE("%s(id=%d)\n", __func__, id); + // retrieve network interface list global variable + struct netif *pnetif_list = netif_list; + // look at each network interface to find the one matching with platform_netif + while (pnetif_list != NULL) { + int8_t current_netif[6] = {0}; + sprintf((char *)current_netif, "%c%c%d", pnetif_list->name[0], pnetif_list->name[1], pnetif_list->num); + // check if the mapped netif name matches with the platform netif name + if (strncmp((char*)current_netif, platform_netif[id], strlen(platform_netif[id])) == 0) { + // store the current lwip netif name + set_lwip_netif_name(id, (char *)current_netif); + + // check if we have this netif id mapped in LLNET_configuration.h + if (id < (sizeof(platform_netif) / sizeof(platform_netif[0]))) { + // we need space for the netif name and the trailing 'NULL'. + int32_t requiredLen = strlen(llnet_netif[id]) + 1; + if (length < requiredLen) { + return J_EINVAL; + } + strcpy((char*)nameReturned, llnet_netif[id]); + return requiredLen; + } else { + return J_EINVAL; + } + } + // not found, look at the next interface + pnetif_list = pnetif_list->next; + } + // error: no address found at the 'idAddr' index + return 0; +} + +// v6 is not supported yet, but here are the v4 and v6 constants +// for the getVMInterfaceAddress protocol between Java and the native stacks + +// ipv4 address info size (tag (1) + IP (4) + prefix (1) + hasBroadcast (1) + broadcast IP (4)) +#define IPV4_ADDR_INFO_SIZE 11 +// ipv6 address info size (tag (1) + IP (16) + prefix (1) +#define IPV6_ADDR_INFO_SIZE 18 + +// ipv4 address tag +#define IPV4_ADDR_TAG 4 +// ipv6 address tag +#define IPV6_ADDR_TAG 6 + +static int32_t _getMaskLen(struct netif *netif) +{ + int32_t len = 0; + u32_t mask = ip4_addr_get_u32(netif_ip4_netmask(netif)); + while (mask) { + mask >>= 1; + len++; + } + return len; +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_getVMInterfaceAddress(int32_t idIf, int32_t idAddr, int8_t* addrInfo, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + // retrieve network interface list global variable + struct netif *pnetif_list = netif_list; + // look at each network interface to find the one matching with stored lwip netif + + while(pnetif_list != NULL){ + int8_t current_netif[6] = {0}; + sprintf((char *)current_netif, "%c%c%d", pnetif_list->name[0], pnetif_list->name[1], pnetif_list->num); + // check if the mapped netif name matches with the lwip netif name + if (strcmp((char*)current_netif, get_lwip_netif_name(idIf)) == 0) { + // interface found, return the configured ip address + // 'idAddr' not take into account here because only one ip address + // is configured per network interface + addrInfo[0] = IPV4_ADDR_TAG; + memcpy(&addrInfo[1], ip_2_ip4(&pnetif_list->ip_addr), sizeof(ip4_addr_t)); + // prefix can be from 0 to 128 + // so we encode it on 1 byte, from 0 to 0x80 + addrInfo[1 + sizeof(ip4_addr_t)] = _getMaskLen(pnetif_list); + // now the broadcast, + if ((pnetif_list->flags & NETIF_FLAG_BROADCAST) == 0) + { + addrInfo[2 + sizeof(ip4_addr_t)] = 0; + } + else + { + u32_t broadcast = ip4_addr_get_u32(netif_ip4_addr(pnetif_list)) | ~ip4_addr_get_u32(netif_ip4_netmask(pnetif_list)); + int32_t pos = 2 + sizeof(ip4_addr_t); + addrInfo[pos++] = 1; + addrInfo[pos++] = (broadcast) & 0xFF; + addrInfo[pos++] = (broadcast >> 8) & 0xFF; + addrInfo[pos++] = (broadcast >> 16) & 0xFF; + addrInfo[pos++] = (broadcast >> 24) & 0xFF; + } + return IPV4_ADDR_INFO_SIZE; + } + + // not found, look at the next interface + pnetif_list = pnetif_list->next; + } + // error: no address found at the 'idAddr' index + return 0; +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_getVMInterfaceAddressesCount(int32_t id, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + return 1; // only one address configuration per network interface +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_getVMInterfacesCount(uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + struct netif *pnetif_list = netif_list; + int32_t ifCnt = 0; + while(pnetif_list != NULL){ + ++ifCnt; + // get next interface, and verify it exists or not + pnetif_list = pnetif_list->next; + } + return ifCnt; +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_isLoopback(int8_t* name, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s for %s\n", __func__, (const char *)name); + #if (defined(LWIP_NETIF_LOOPBACK) && (LWIP_NETIF_LOOPBACK != 0)) + char *llnet_netif[] = LLNET_NETIF_NAMES; + char *platform_netif[] = PLATFORM_NETIF_NAMES; + for (int32_t netif_idx = 0; netif_idx < (sizeof(llnet_netif) / sizeof(llnet_netif[0])); netif_idx++) { + if (strcmp((char *)name, llnet_netif[netif_idx]) == 0) { + return (strcmp("lo", platform_netif[netif_idx]) == 0) ? 0 : 1; // 0 means true + } + } + return 1; // 1 means false + #else + return 1; // 1 means false + #endif +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_isPointToPoint(int8_t* name, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + return 1; // 0 means true +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_isUp(int8_t* name, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + struct netif *pnetif = getNetworkInterface(name); + if(pnetif != NULL){ + return netif_is_up(pnetif) ? 0 : 1; // 0 means true + } + return J_EUNKNOWN; +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_supportsMulticast(int8_t* name, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + struct netif *pnetif = getNetworkInterface(name); + if(pnetif != NULL){ + return (pnetif->flags & NETIF_FLAG_BROADCAST) != 0 ? 0 : 1; // 0 means true + } + return J_EUNKNOWN; +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_getHardwareAddress(int8_t* name, int32_t length, int8_t* hwAddr, int32_t hwAddrMaxLength, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + struct netif *pnetif = getNetworkInterface(name); + if(pnetif != NULL){ + memcpy(hwAddr, pnetif->hwaddr, pnetif->hwaddr_len); + return pnetif->hwaddr_len; + } + // hardware address not found + return 0; +} + +int32_t LLNET_NETWORKINTERFACE_IMPL_getMTU(int8_t* name, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s\n", __func__); + struct netif *pnetif = getNetworkInterface(name); + if(pnetif != NULL){ + if (pnetif->mtu == 0) { + // -1 means unknown MTU value + return -1; + } + return pnetif->mtu; + } + // hardware address not found + return J_EUNKNOWN; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/LLNET_SOCKETCHANNEL_bsd.c b/bsp/projects/microej/net/src/LLNET_SOCKETCHANNEL_bsd.c new file mode 100644 index 0000000..db27d2e --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_SOCKETCHANNEL_bsd.c @@ -0,0 +1,360 @@ +/* + * C + * + * Copyright 2014-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_SOCKETCHANNEL 2.1.0 implementation over BSD-like API. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#include + +#include +#include + +#include "LLNET_Common.h" +#if LLNET_AF & LLNET_AF_IPV6 +#include +#include +#include +#include +#endif +#include +#include "LLNET_CONSTANTS.h" +#include "LLNET_NETWORKADDRESS_impl.h" +#include "LLNET_ERRORS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static int32_t SocketChanel_Address(int32_t fd, int8_t* name, + int32_t nameLength, uint8_t localAddress); + +static int32_t SocketChanel_Port(int32_t fd, uint8_t localPort); + +int32_t LLNET_SOCKETCHANNEL_IMPL_connect(int32_t fd, int8_t* addr, + int32_t length, int32_t port, int32_t timeout, uint8_t retry) { + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, port=%d, timeout=%d)\n", __func__, + SNI_getCurrentJavaThreadID(), fd, port, timeout); + + if (llnet_is_ready() == false) { + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t res; + + if (retry) { + //check if the socket is connected + int32_t selectRes = non_blocking_select(fd, SELECT_WRITE); + if (selectRes == -1) { + return map_to_java_exception(llnet_errno(fd)); + } else if (selectRes) { + // data are available in fd + union llnet_sockaddr sockaddr = { 0 }; + uint32_t addrlen = sizeof(sockaddr); + int32_t peerRes = llnet_getpeername(fd, &sockaddr.addr, + (socklen_t*) &addrlen); + if (peerRes == 0) { + //the socket is connected to a remote host + return 1; //success + } else { + return map_to_java_exception(llnet_errno(fd)); + } + + } else { + //a timeout expires during the first connect + return J_ETIMEDOUT; + } + } else { // retry == false + + union llnet_sockaddr sockaddr = { 0 }; + int sockaddr_sizeof = 0; + +#if LLNET_AF == LLNET_AF_IPV4 + if (length == sizeof(in_addr_t)) { + sockaddr.in.sin_family = AF_INET; + sockaddr.in.sin_port = llnet_htons(port); + sockaddr.in.sin_addr.s_addr = *((in_addr_t*) addr); + sockaddr_sizeof = sizeof(struct sockaddr_in); + } +#endif + +#if LLNET_AF == LLNET_AF_DUAL + if(length == sizeof(in_addr_t) && (uint32_t)SNI_getArrayLength(addr) >= sizeof(struct in6_addr)) { + // Convert IPv4 into IPv6 directly in the addr array + map_ipv4_into_ipv6((in_addr_t*)addr, (struct in6_addr*)addr); + + // Now length of the address in addr is sizeof(struct in6_addr) + length = sizeof(struct in6_addr); + // continue in the following if + } +#endif + +#if LLNET_AF & LLNET_AF_IPV6 + if(length == sizeof(struct in6_addr)) { + char ipAddress[NI_MAXHOST]; + sockaddr.in6.sin6_family = AF_INET6; + sockaddr.in6.sin6_port = llnet_htons(port); + // Convert the incoming IP address to ASCII, lookup the interface and set the scope ID + if(inet_ntop(AF_INET6, addr, ipAddress, NI_MAXHOST) != NULL) { + sockaddr.in6.sin6_scope_id=getScopeForIp(ipAddress); + } else { + LLNET_DEBUG_TRACE("%s[thread %d] inet_ntop failed, errno = %d\n", __func__, SNI_getCurrentJavaThreadID(), llnet_errno(fd)); + return J_EINVAL; + } + memcpy((void*)&sockaddr.in6.sin6_addr, addr, sizeof(struct in6_addr)); + sockaddr_sizeof = sizeof(struct sockaddr_in6); + } +#endif + + if (sockaddr_sizeof == 0) { + return J_EINVAL; + } + + // Set nonblocking mode. + bool was_non_blocking = is_socket_non_blocking(fd); + if (was_non_blocking == false) { + res = set_socket_non_blocking(fd, true); + if (res != 0) { + return map_to_java_exception(llnet_errno(fd)); + } + } + + int32_t connectRes = llnet_connect(fd, &sockaddr.addr, sockaddr_sizeof); + int32_t connectErrno = llnet_errno(fd); + + // Set blocking mode. + if (was_non_blocking == false) { + // The socket was blocking initially. + res = set_socket_non_blocking(fd, false); + if (res != 0) { + return map_to_java_exception(llnet_errno(fd)); + } + } + + if (connectRes == -1) { + if (connectErrno == EINPROGRESS) { + //The connection can not be completed immediately. + + if (was_non_blocking == true) { + // the socket is in non-blocking mode and the connection did not immediately succeed + return 0; + } + + // A blocking request on write operation is added in the dispatch event queue for completion. + int32_t asyncSelectRes = async_select(fd, SELECT_WRITE, timeout, + NULL); + if (asyncSelectRes == 0) { + // request added in the queue + LLNET_DEBUG_TRACE("Connect has blocked without result\n"); + return J_NET_NATIVE_CODE_BLOCKED_WITHOUT_RESULT; + } + // requests queue limit reached + LLNET_DEBUG_TRACE("Blocking Request Queue Limit Reached\n"); + return J_ASYNC_BLOCKING_REQUEST_QUEUE_LIMIT_REACHED; + } else { + LLNET_DEBUG_TRACE( + "[ERROR] Connection failed (retry=%d, errno=%d)\n", + retry, connectErrno); + return map_to_java_exception(connectErrno); + } + } else { + return 1; // connected + } + } +} + +int32_t LLNET_SOCKETCHANNEL_IMPL_getLocalPort(int32_t fd, uint8_t retry) { + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X)\n", __func__, + SNI_getCurrentJavaThreadID(), fd); + + (void)retry; + + if (llnet_is_ready() == false) { + return J_NETWORK_NOT_INITIALIZED; + } + + return SocketChanel_Port(fd, JTRUE); +} + +int32_t LLNET_SOCKETCHANNEL_IMPL_getLocalAddress(int32_t fd, int8_t* name, + int32_t length, uint8_t retry) { + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X)\n", __func__, + SNI_getCurrentJavaThreadID(), fd); + + (void)retry; + + if (llnet_is_ready() == false) { + return J_NETWORK_NOT_INITIALIZED; + } + + return SocketChanel_Address(fd, name, length, JTRUE); +} + +int32_t LLNET_SOCKETCHANNEL_IMPL_getPeerPort(int32_t fd, uint8_t retry) { + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X)\n", __func__, + SNI_getCurrentJavaThreadID(), fd); + + (void)retry; + + if (llnet_is_ready() == false) { + return J_NETWORK_NOT_INITIALIZED; + } + + return SocketChanel_Port(fd, JFALSE); +} + +int32_t LLNET_SOCKETCHANNEL_IMPL_getPeerAddress(int32_t fd, int8_t* name, + int32_t length, uint8_t retry) { + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X)\n", __func__, + SNI_getCurrentJavaThreadID(), fd); + + (void)retry; + + if (llnet_is_ready() == false) { + return J_NETWORK_NOT_INITIALIZED; + } + + return SocketChanel_Address(fd, name, length, JFALSE); +} + +static int32_t SocketChanel_Port(int32_t fd, uint8_t localPort) { + union llnet_sockaddr sockaddr = { 0 }; + + uint32_t addrlen = sizeof(sockaddr); + int32_t ret = -1; + if (localPort) { + ret = llnet_getsockname(fd, &sockaddr.addr, (socklen_t*) &addrlen); + } else { + ret = llnet_getpeername(fd, &sockaddr.addr, (socklen_t*) &addrlen); + } + + if (ret == 0) { +#if LLNET_AF & LLNET_AF_IPV4 + if (sockaddr.addr.sa_family == AF_INET) { + return llnet_ntohs(sockaddr.in.sin_port); + } +#endif +#if LLNET_AF & LLNET_AF_IPV6 + if(sockaddr.addr.sa_family == AF_INET6) { + return llnet_ntohs(sockaddr.in6.sin6_port); + } +#endif + return J_EUNKNOWN; + } + + return map_to_java_exception(llnet_errno(fd)); +} + +static int32_t SocketChanel_Address(int32_t fd, int8_t* name, + int32_t nameLength, uint8_t localAddress) { + + union llnet_sockaddr sockaddr = { 0 }; + uint32_t addrlen = sizeof(sockaddr); + int32_t ret = -1; + if (localAddress) { + ret = llnet_getsockname(fd, &sockaddr.addr, (socklen_t*) &addrlen); + LLNET_DEBUG_TRACE("getsockname(fd=0x%X) ret=%d errno=%d\n", fd, ret, + llnet_errno(fd)); + } else { + ret = llnet_getpeername(fd, &sockaddr.addr, (socklen_t*) &addrlen); + LLNET_DEBUG_TRACE("getpeername(fd=0x%X) ret=%d errno=%d\n", fd, ret, + llnet_errno(fd)); + } + if (ret == 0) { +#if LLNET_AF & LLNET_AF_IPV4 + if (sockaddr.addr.sa_family == AF_INET) { + if (!localAddress + && (sockaddr.in.sin_addr.s_addr == 0 + || sockaddr.in.sin_port == llnet_htons(0))) { + //not connected + return J_ENOTCONN; + } + if ((uint32_t)nameLength < sizeof(in_addr_t)) { + return J_EINVAL; + } + *(in_addr_t*) name = sockaddr.in.sin_addr.s_addr; + return sizeof(in_addr_t); + } +#endif +#if LLNET_AF & LLNET_AF_IPV6 + if(sockaddr.addr.sa_family == AF_INET6) { + if(!localAddress && (sockaddr.in6.sin6_addr.s6_addr == 0 || sockaddr.in6.sin6_port == llnet_htons(0))) { + //not connected + return J_ENOTCONN; + } + if((uint32_t)nameLength < sizeof(struct in6_addr)) { + return J_EINVAL; + } + memcpy(name, (void *)&(sockaddr.in6.sin6_addr), sizeof(struct in6_addr)); + return sizeof(struct in6_addr); + } +#endif + return J_EUNKNOWN; + } + return map_to_java_exception(llnet_errno(fd)); +} + +int32_t LLNET_SOCKETCHANNEL_IMPL_socket(uint8_t stream, uint8_t retry) { + LLNET_DEBUG_TRACE("%s[thread %d](stream=%d)\n", __func__, + SNI_getCurrentJavaThreadID(), stream); + + (void)retry; + + if (llnet_is_ready() == false) { + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t ret; + int32_t sock_protocol = 0; //default value + int domain; + +// When IPv6 is available, always use IPv6 (even for IPv4 connections) +#if LLNET_AF & LLNET_AF_IPV6 + domain = AF_INET6; +#else // only IPv4 + domain = AF_INET; +#endif + + ret = llnet_socket(domain, stream ? SOCK_STREAM : SOCK_DGRAM, + sock_protocol); + if (ret == -1) { + int32_t err = map_to_java_exception(llnet_errno(-1)); + return err; + } + + int32_t fd = ret; + +// If dual stack IPv4/IPv6 +#if LLNET_AF == LLNET_AF_DUAL + // Disable IPV6_V6ONLY to ensure dual-socket support + int ipv6_only = 0; + ret = llnet_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6_only, sizeof(int)); + if (ret == -1) { + int32_t err = map_to_java_exception(llnet_errno(fd)); + close(fd); + return err; + } +#endif + + return fd; +} + +int32_t LLNET_SOCKETCHANNEL_IMPL_serverSocket(uint8_t retry) { + return LLNET_SOCKETCHANNEL_IMPL_socket(JTRUE, retry); +} + +int32_t LLNET_SOCKETCHANNEL_IMPL_multicastSocket(uint8_t retry) { + return LLNET_SOCKETCHANNEL_IMPL_socket(JFALSE, retry); +} + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/net/src/LLNET_STREAMSOCKETCHANNEL_bsd.c b/bsp/projects/microej/net/src/LLNET_STREAMSOCKETCHANNEL_bsd.c new file mode 100644 index 0000000..fa5ba7c --- /dev/null +++ b/bsp/projects/microej/net/src/LLNET_STREAMSOCKETCHANNEL_bsd.c @@ -0,0 +1,175 @@ +/* + * C + * + * Copyright 2014-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_STREAMSOCKETCHANNEL 2.1.0 implementation over BSD-like API. + * @author MicroEJ Developer Team + * @version 1.4.2 + * @date 19 April 2022 + */ + +#include + +#include +#include +#include "LLNET_CONSTANTS.h" +#include +#include "LLNET_ERRORS.h" +#include "LLNET_Common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef USE_MSG_PEEK_FOR_AVAILABLE +// Define the buffers used for LLNET_STREAMSOCKETCHANNEL_IMPL_available() function. +// The LLNET_configuration.h must define the size of this buffer: NET_EMBEDDED_AVAILABLE_BUFFER_SIZE. +uint8_t NET_EMBEDDED_AVAILABLE_BUFFER[NET_EMBEDDED_AVAILABLE_BUFFER_SIZE]; +#endif + +int32_t StreamSocketChannel_accept(int32_t fd) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X)\n", __func__, SNI_getCurrentJavaThreadID(), fd); + int32_t ret; + ret = llnet_accept(fd, NULL, NULL); + if(ret == -1){ + LLNET_DEBUG_TRACE("Error on accept (fd=0x%X)\n", fd); + return map_to_java_exception(llnet_errno(fd)); + } + + LLNET_DEBUG_TRACE("Successful accept OK fd=0x%X\n", ret); + return ret; +} + +int32_t StreamSocketChannel_writeByteBufferNative(int32_t fd, int8_t* src, int32_t offset, int32_t length) +{ + LLNET_DEBUG_TRACE("%s[thread %d]\n", __func__, SNI_getCurrentJavaThreadID()); + int32_t ret; + ret = llnet_send(fd, src+offset, length, 0); + LLNET_DEBUG_TRACE("sent bytes size = %d (length=%d)\n", ret, length); + if(ret == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + return ret; +} + +int32_t StreamSocketChannel_readByteBufferNative(int32_t fd, int8_t* dst, int32_t offset, int32_t length) +{ + LLNET_DEBUG_TRACE("%s[thread %d]\n", __func__, SNI_getCurrentJavaThreadID()); + int32_t ret; + ret = llnet_recv(fd, dst+offset, length, 0); + LLNET_DEBUG_TRACE("nb received data : %d errno=%d\n", ret, llnet_errno(fd)); + if(ret == -1){ + return map_to_java_exception(llnet_errno(fd)); + } + + if (0 == ret) { + return -1; //EOF + } + return ret; +} + +int32_t LLNET_STREAMSOCKETCHANNEL_IMPL_readByteBufferNative(int32_t fd, int32_t kind, int8_t* dst, int32_t offset, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, kind=%d, retry=%d)\n", __func__, SNI_getCurrentJavaThreadID(), fd, kind, retry); + + (void)kind; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t selectRes = non_blocking_select(fd, SELECT_READ); + + if(selectRes == 0){ + return net_asyncOperation(fd, SELECT_READ, retry); + }else{ + return StreamSocketChannel_readByteBufferNative(fd, dst, offset, length); + } +} + +int32_t LLNET_STREAMSOCKETCHANNEL_IMPL_writeByteBufferNative(int32_t fd, int32_t kind, int8_t* src, int32_t offset, int32_t length, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d]\n", __func__, SNI_getCurrentJavaThreadID()); + + (void)kind; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t selectRes = non_blocking_select(fd, SELECT_WRITE); + + if(selectRes == 0){ + return net_asyncOperation(fd, SELECT_WRITE, retry); + }else{ + return StreamSocketChannel_writeByteBufferNative(fd, src, offset, length); + } +} + +int32_t LLNET_STREAMSOCKETCHANNEL_IMPL_available(int32_t fd, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X)\n", __func__, SNI_getCurrentJavaThreadID(), fd); + + (void)retry; + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + +#if !defined(USE_MSG_PEEK_FOR_AVAILABLE) && !defined(USE_SOCK_OPTION_FOR_AVAILABLE) + int32_t size; + int32_t res = llnet_ioctl(fd, FIONREAD, &size); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X) size=%d errno=%d res=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, size, llnet_errno(fd), res); + if(res == 0){ + return size; + } + // error on ioctl + return map_to_java_exception(llnet_errno(fd)); +#elif defined(USE_MSG_PEEK_FOR_AVAILABLE) + int32_t size = llnet_recv(fd, NET_EMBEDDED_AVAILABLE_BUFFER, NET_EMBEDDED_AVAILABLE_BUFFER_SIZE, MSG_PEEK | MSG_DONTWAIT); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X) size=%d errno=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, size, llnet_errno(fd)); + if(size >= 0){ + return size; + } + if(llnet_errno(fd) == EAGAIN){ + return 0; + } + return map_to_java_exception(llnet_errno(fd)); +#else + int32_t size; + int32_t optlen = sizeof(int32_t); + int32_t res = llnet_getsockopt (fd, SOL_SOCKET, SO_RXDATA, &size, (socklen_t *)&optlen); + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X) size=%d errno=%d res=%d\n", __func__, SNI_getCurrentJavaThreadID(), fd, size, llnet_errno(fd), res); + if(res == 0){ + return size; + } + return map_to_java_exception(llnet_errno(fd)); +#endif +} + +int32_t LLNET_STREAMSOCKETCHANNEL_IMPL_accept(int32_t fd, uint8_t retry) +{ + LLNET_DEBUG_TRACE("%s[thread %d](fd=0x%X, retry=%d)\n", __func__, SNI_getCurrentJavaThreadID(), fd, retry); + + if(llnet_is_ready() == false){ + return J_NETWORK_NOT_INITIALIZED; + } + + int32_t selectRes = non_blocking_select(fd, SELECT_READ); + + if(selectRes == 0){ + return net_asyncOperation(fd, SELECT_READ, retry); + }else{ + return StreamSocketChannel_accept(fd); + } +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/async_select.c b/bsp/projects/microej/net/src/async_select.c new file mode 100644 index 0000000..9743dbe --- /dev/null +++ b/bsp/projects/microej/net/src/async_select.c @@ -0,0 +1,661 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief Asynchronous network select implementation + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 16 May 2022 + */ + +#include "async_select.h" +#include "async_select_configuration.h" +#include "async_select_cache.h" +#include +#include +#include "LLNET_Common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * Sanity check between the expected version of the configuration and the actual version of + * the configuration. + * If an error is raised here, it means that a new version of the CCO has been installed and + * the configuration async_select_configuration.h must be updated based on the one provided + * by the new CCO version. + */ +#if ASYNC_SELECT_CONFIGURATION_VERSION != 3 + + #error "Version of the configuration file async_select_configuration.h is not compatible with this implementation." + +#endif + +/** @brief An asynchronous select request */ +typedef struct async_select_Request{ + int32_t fd; + int32_t java_thread_id; + // Absolute time for timeout in milliseconds, 0 if no timeout + int64_t absolute_timeout_ms; + SELECT_Operation operation; + struct async_select_Request* next; +} async_select_Request; + +/** + * @brief Enter critical section for the async_select component. + */ +extern void async_select_lock(void); +/** + * @brief Exit critical section for the async_select component. + */ +extern void async_select_unlock(void); + +/** + * @brief External function used to retrieve currentTime (defined in LLMJVM) + */ +extern int64_t LLMJVM_IMPL_getCurrentTime__Z(uint8_t system); + +/** + * Gets the system time in milliseconds (int64_t). This time is independent from any user considerations + * and cannot be changed. + */ +#define async_select_get_current_time_ms() LLMJVM_IMPL_getCurrentTime__Z(1) // 1 means that system time is required + + +/* + * See implementations for descriptions. + */ +static void async_select_do_select(void); +static void async_select_update_notified_requests(void); +static int32_t async_select_get_notify_fd(void); +static async_select_Request* async_select_allocate_request(void); +static async_select_Request* async_select_free_used_request(async_select_Request* request, async_select_Request* previous_request_in_used_fifo); +static void async_select_free_unused_request(async_select_Request* request); +static int32_t async_select_send_new_request(async_select_Request* request); +static void async_select_notify_select(void); +void async_select_request_fifo_init(void); + +/** + * @brief Pool of requests. Used to reserve MAX_NB_ASYNC_SELECT async select requests. + */ +static async_select_Request all_requests[MAX_NB_ASYNC_SELECT]; +/** + * @brief Linked-list of free requests that can be allocated using async_select_allocate_request(). + */ +static async_select_Request* free_requests_fifo; +/** + * @brief Linked-list of used requests. + */ +static async_select_Request* used_requests_fifo; +/** + * @brief File descriptor set for SELECT_READ requests. + */ +static fd_set read_fds; +/** + * @brief File descriptor set for SELECT_WRITE requests. + */ +static fd_set write_fds; +/** + * @brief Used to unblock select() function call. + */ + +#ifdef ASYNC_SELECT_USE_PIPE_FOR_NOTIFICATION + +static int8_t pipe_fds_initialized = 0; +static int32_t pipe_fds[2]; + +#else + +volatile static int32_t notify_fd_cache = -1; + +#endif //ASYNC_SELECT_USE_PIPE_FOR_NOTIFICATION + +/** + * @brief set to one once the FIFOs are initialized. + */ +volatile static uint8_t async_select_fifo_initialized = 0; + +/** + * @brief Execute a select() for the given file descriptor and operation without blocking. + * + * @param fd the file descriptor. + * @param operation the operation (read or write) we want to monitor with the select(). + * + * @return select() result. + */ +int32_t non_blocking_select(int32_t fd, SELECT_Operation operation){ + struct timeval zero_timeout; + zero_timeout.tv_sec = 0; + zero_timeout.tv_usec = 0; + fd_set io_fds; + fd_set* read_fds_ptr; + fd_set* write_fds_ptr; + FD_ZERO(&io_fds); + FD_SET(fd, &io_fds); + + if(operation == SELECT_READ){ + read_fds_ptr = &io_fds; + write_fds_ptr = NULL; + } + else { // SELECT_WRITE + read_fds_ptr = NULL; + write_fds_ptr = &io_fds; + } + + int32_t selectRes = select(fd+1, read_fds_ptr, write_fds_ptr, NULL, &zero_timeout); + + return selectRes; +} + +/** + * @brief Executes asynchronously a select() operation for the given file descriptor. + * + * This function will suspend the execution of the current Java thread using + * SNI_suspendCurrentJavaThreadWithCallback(). Once the select() succeeds the Java + * thread is resumed and the given SNI callback is called. * + * + * @param fd the file descriptor. + * @param operation the operation (read or write) we want to monitor with the select(). + * @param timeout_ms timeout in millisecond + * @param the SNI callback to call when the Java thread is resumed or timeout occurs. + * + * @return 0 on success, -1 on failure. + */ +int32_t async_select(int32_t fd, SELECT_Operation operation, int64_t timeout_ms, SNI_callback callback){ + + int32_t res; + + async_select_Request* request = async_select_allocate_request(); + if(request == NULL){ + // No request available :-( + return -1; + } + + int32_t java_thread_id = SNI_getCurrentJavaThreadID(); + if(java_thread_id == SNI_ERROR){ + // Not called from the VM task + async_select_free_unused_request(request); + return -1; + } + + LLNET_DEBUG_TRACE("async_select: async_select on fd=0x%X operation=%s thread 0x%X\n", fd, operation==SELECT_READ ? "read":"write", java_thread_id); + request->java_thread_id = java_thread_id; + request->fd = fd; + request->operation = operation; + if(timeout_ms != 0){ + request->absolute_timeout_ms = async_select_get_current_time_ms() + timeout_ms; + } + else { // infinite timeout + request->absolute_timeout_ms = 0; + } + + res = async_select_set_socket_absolute_timeout_in_cache(fd, request->absolute_timeout_ms); + + if(res != 0){ + async_select_free_unused_request(request); + return -1; + } + + SNI_suspendCurrentJavaThreadWithCallback(0, callback, NULL); + res = async_select_send_new_request(request); + + return res; +} + +/** + * @brief Initializes the requests FIFOs. + * This function must be called prior to any call of async_select(). + * It can be called several times. + */ +void async_select_request_fifo_init(){ + // Init free requests FIFO + async_select_lock(); + if(async_select_fifo_initialized == 0){ + free_requests_fifo = &all_requests[0]; + for(int i=0 ; ifd == fd){ + // Modify timeout value so that when the task will check this request + // it will detect a timeout. + request->absolute_timeout_ms = 1; + } + request = request->next; + } + + async_select_unlock(); + + async_select_notify_select(); + +#else + + (void)fd; + +#endif //ASYNC_SELECT_CLOSE_UNBLOCK_SELECT + +} + +/** + * @brief The entry point for the async_select task. + * This function must be called from a dedicated task. + */ +void async_select_task_main(){ + + llnet_init(); + + async_select_request_fifo_init(); + + while(true){ + // Execute a select(). + async_select_do_select(); + // Update the received request depending on the select() results. + async_select_update_notified_requests(); + } +} + +/** + * @brief Returns the file descriptor created just to unlock the select() when + * we want to notify the async_select task that a new request has been + * sent. + */ +static int32_t async_select_get_notify_fd(){ + + +#ifdef ASYNC_SELECT_USE_PIPE_FOR_NOTIFICATION + + if(pipe_fds_initialized == 0){ + if(pipe(pipe_fds) == -1 || + set_socket_non_blocking(pipe_fds[0], true) != 0 || + set_socket_non_blocking(pipe_fds[1], true) != 0){ + //error : can not create the pipe + return -1; + } + pipe_fds_initialized = 1; + } + return pipe_fds[0]; + +#else + + // Just take and release the lock to ensure that the VM task has not been preempted in the + // middle of async_select_notify_select() (i.e. notify_fd_cache has been set to -1 but socket + // has not been closed yet). + async_select_lock(); + int32_t notify_fd = notify_fd_cache; + async_select_unlock(); + if(notify_fd != -1){ + // fd already exists + return notify_fd; + } + + int domain; + +// If IPv6 or IPv4+IPv6 configuration, then use IPv6. Otherwise (only IPv4 configuration) use IPv4. +#if LLNET_AF & LLNET_AF_IPV6 + domain = AF_INET6; +#else // only IPv4 + domain = AF_INET; +#endif + // Create a simple local TCP server to wait on and call close when we want to unblock the select + notify_fd = llnet_socket(domain, SOCK_STREAM, IPPROTO_TCP); + if(notify_fd != -1){ + + +#if LLNET_AF & LLNET_AF_IPV6 + struct sockaddr_in6 sockaddr = {0}; + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = llnet_htons(0); + memcpy(&sockaddr.sin6_addr, &ASYNC_SELECT_NOTIFY_SOCKET_BIND_IN6ADDR, sizeof(sockaddr.sin6_addr)); +#else + struct sockaddr_in sockaddr = {0}; + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = llnet_htons(0); + sockaddr.sin_addr.s_addr = ASYNC_SELECT_NOTIFY_SOCKET_BIND_INADDR; +#endif + int32_t ret = llnet_bind(notify_fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + if(ret != -1){ + ret = llnet_listen(notify_fd, 1); + if(ret != -1){ + // Save it for next time to avoid a new creation. + notify_fd_cache = notify_fd; + return notify_fd; + } + } + + // Something was wrong when configuring the notify_fd + llnet_close(notify_fd); + } + + return -1; + +#endif // ASYNC_SELECT_USE_PIPE_FOR_NOTIFICATION +} + +/** + * @brief Executes the select() operation for the file descriptors referenced by the received requests. + */ +static void async_select_do_select(){ + + async_select_Request* request; + + int32_t notify_fd = async_select_get_notify_fd(); + // Used to save the highest fd found in the requests. + int32_t max_request_fd = notify_fd; + // Used to save the lower timeout found in the requests. + int64_t min_absolute_timeout_ms = INT64_MAX; + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + + // add the notify file descriptor to the read select list + if(notify_fd != -1){ + FD_SET(notify_fd, &read_fds); + } + else { + // We were not able to create the socket to unlock the select. + // To prevent an infinite lock of the select we will poll for + // incoming messages by setting a timeout to the select. + min_absolute_timeout_ms = async_select_get_current_time_ms() + ASYNC_SELECT_POLLING_MODE_TIMEOUT_MS; + LLNET_DEBUG_TRACE("async_select: WARNING: notify_fd cannot be allocated, fall back in polling mode\n"); + } + + // ----------------------------------------------------------------- + // Add read/write waiting operations in file descriptors select list + // ----------------------------------------------------------------- + request = used_requests_fifo; + while(request != NULL){ + int32_t request_fd = request->fd; + if(request_fd > max_request_fd){ + // Save the highest fd + max_request_fd = request_fd; + } + + int64_t request_absolute_timeout_ms = request->absolute_timeout_ms; + if(request_absolute_timeout_ms != 0 && request_absolute_timeout_ms < min_absolute_timeout_ms){ + // Save the lowest timeout + min_absolute_timeout_ms = request_absolute_timeout_ms; + } + + if(request->operation == SELECT_READ){ + FD_SET(request_fd, &read_fds); + } + else { // operation == SELECT_WRITE + FD_SET(request_fd, &write_fds); + } + + request = request->next; + } + + // ----------------------------- + // Compute select timeout value + // ----------------------------- + + // Timeout to use for the select + struct timeval select_timeout = {0}; + struct timeval* select_timeout_ptr; + + if(min_absolute_timeout_ms != INT64_MAX){ + // At least one request has a timeout. + select_timeout_ptr = &select_timeout; + int64_t min_relative_timeout_ms = min_absolute_timeout_ms - async_select_get_current_time_ms(); + // Saturate the relative timeout to a positive value + if(min_relative_timeout_ms < 0){ + // 0 means no timeout + min_relative_timeout_ms = 0; + } + time_ms_to_timeval(min_relative_timeout_ms, select_timeout_ptr); + } + else { +#ifndef ASYNC_SELECT_USE_MAX_INFINITE_TIMEOUT + // No request has timeout -> NULL timeout means infinite timeout + select_timeout_ptr = NULL; +#else + // No request has timeout -> Use maximum timeout for a simulated infinite timeout + select_timeout_ptr = &select_timeout; + select_timeout.tv_sec = ASYNC_SELECT_MAX_TV_SEC_VALUE; + select_timeout.tv_usec = ASYNC_SELECT_MAX_TV_USEC_VALUE; +#endif + } + + + // -------------- + // Do the select + // -------------- + LLNET_DEBUG_TRACE("async_select: select (timeout sec=%d usec=%d)\n", (int32_t)select_timeout.tv_sec, (int32_t)select_timeout.tv_usec); + int32_t res = select(max_request_fd+1, &read_fds, &write_fds, NULL, select_timeout_ptr); + + if(res >= 0 || llnet_errno(-1) == EBADF){ + //errno == EBADF when one of fd in the fdset is invalid/closed + //We consider that the select was succeeded in this case + //because all operations through an invalid/closed fd would not block + +#ifdef ASYNC_SELECT_USE_PIPE_FOR_NOTIFICATION + //check if notify_fd is selected and cleanup the pipe + if(FD_ISSET(notify_fd, &read_fds)){ + //cleanup pipe + char bytes[1]; + while(read(notify_fd, (void*)bytes, 1) > 0); //non blocking pipe fds + } +#endif + + LLNET_DEBUG_TRACE("async_select: select finished %d sockets available\n", res); + } +} + +/** + * @brief After the execution of the select() operation, update the status of the requests + * that have been notified by the select() or have reached the timemout. + */ +static void async_select_update_notified_requests(){ + + async_select_Request* request; + async_select_Request* previous_request = NULL; + int64_t current_time_ms = async_select_get_current_time_ms(); + + async_select_lock(); + // Browse all the requests to find which have been modified + request = used_requests_fifo; + while(request != NULL){ + int32_t request_fd = request->fd; + bool request_timeout_reached; + + // Check if timeout has been reached. + if(request->absolute_timeout_ms != 0 && request->absolute_timeout_ms <= current_time_ms){ + request_timeout_reached = true; + } + else { + request_timeout_reached = false; + } + + if((request->operation == SELECT_READ && FD_ISSET(request_fd, &read_fds)) // data received + || (request->operation == SELECT_WRITE && FD_ISSET(request_fd, &write_fds)) // or data sent + || (request_timeout_reached) // or timeout reached + ){ + // Request done. + LLNET_DEBUG_TRACE("async_select: request done for fd=0x%X operation=%s notify thread 0x%X (%s)\n", request_fd, request->operation==SELECT_READ ? "read":"write", request->java_thread_id, request_timeout_reached==true ? "timeout":"no timeout"); + SNI_resumeJavaThread(request->java_thread_id); + request = async_select_free_used_request(request, previous_request); + //previous_request is still the same because we have removed request from the used FIFO + } + else { + previous_request = request; + request = request->next; + } + } + async_select_unlock(); +} + +/** + * @brief Remove the given request from the used FIFO and put it in the free FIFO. + * + * This function is NOT thread safe. + * + * @return the next request in the used FIFO. + */ +static async_select_Request* async_select_free_used_request(async_select_Request* request, async_select_Request* previous_request_in_used_fifo){ + + async_select_Request* next_request; + + next_request = request->next; + + // Remove the request from the used FIFO + if(previous_request_in_used_fifo != NULL){ + previous_request_in_used_fifo->next = next_request; + } + else{ + // The request was the first in the used list + used_requests_fifo = next_request; + } + + // Add the request into the free FIFO + request->next = free_requests_fifo; + free_requests_fifo = request; + + return next_request; +} + +/** + * @brief Put the given request in the free FIFO. + * The request must not be in the used FIFO. + * + * This function is thread safe. + */ +static void async_select_free_unused_request(async_select_Request* request){ + + async_select_lock(); + + // Add the request into the free FIFO + request->next = free_requests_fifo; + free_requests_fifo = request; + + async_select_unlock(); +} + +/** + * @brief Notifies the async_select task that a new request must be managed. + */ +static int32_t async_select_send_new_request(async_select_Request* request){ + + async_select_lock(); + // Add the request in the used FIFO + request->next = used_requests_fifo; + used_requests_fifo = request; + async_select_unlock(); + + // Notify the async_select task + async_select_notify_select(); + + return 0; +} + +/** + * @brief Find a free request and returns it. + * The returned request is not put it in the used requests FIFO. + * It must be either put in the used requests FIFO using async_select_send_new_request() + * or put back in the free requests FIFO on error using async_select_free_unused_request(). + * + * This function is thread safe. + * + * @return null if no request available. + */ +static async_select_Request* async_select_allocate_request(){ + + async_select_lock(); + + async_select_Request* new_request = free_requests_fifo; + if(new_request != NULL){ + // Remove the request from the free FIFO + free_requests_fifo = new_request->next; + } + // else: no request available + + async_select_unlock(); + + return new_request; +} + +/** + * @brief Unlock the select operation. + * + * @return 0 on success, a negative value on error. + */ +static void async_select_notify_select(){ + + int32_t res = 0; + int32_t notify_fd; + +#ifdef ASYNC_SELECT_USE_PIPE_FOR_NOTIFICATION + + if(pipe_fds_initialized == 1){ + //Write through the pipe to cancel the current (or the next) blocking select operation. + char bytes[1] = {1}; + notify_fd = pipe_fds[1]; + res = write(notify_fd, (void*)bytes, 1); //pipe_fds[1] refers to the write end of the pipe. + } + else { + notify_fd = -1; + } + +#else + + async_select_lock(); + + notify_fd = notify_fd_cache; + if(notify_fd != -1){ + // async_select task is blocked on select operation. Call + // close function on notify_fd socket to unblock the select. + // WARNING: these two operations must be atomic because we don't want + // the async_selec task to create a new socket while we have not closed + // this one. + notify_fd_cache = -1; + res = llnet_close(notify_fd); + } + // else: + // The notify_fd_cache is not yet defined. It is not a problem because the + // select task will browse the requests list later (after notify_fd_cache creation). + // and so manage the request modification. + + async_select_unlock(); + + +#endif // ASYNC_SELECT_USE_PIPE_FOR_NOTIFICATION + + if(res == -1){ + LLNET_DEBUG_TRACE("Error on notify select (notify_fd: 0x%X errno: %d)\n", notify_fd, llnet_errno(notify_fd)); + } +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/async_select_cache.c b/bsp/projects/microej/net/src/async_select_cache.c new file mode 100644 index 0000000..6f6942c --- /dev/null +++ b/bsp/projects/microej/net/src/async_select_cache.c @@ -0,0 +1,148 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief Socket timeout cache implementation + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 16 May 2022 + */ + +#include "async_select_cache.h" +#include "LLNET_Common.h" +#include "async_select_configuration.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Socket timeout cache structure + */ +typedef struct async_select_sock_timeout { + int32_t fd; + int32_t timeout; + int64_t absolute_timeout; +} async_select_sock_timeout; + +/** + * @brief Cache of socket timeouts. Used to reserve ASYNC_SELECT_TIMEOUT_CACHE_SIZE structures. + */ +static async_select_sock_timeout async_select_sockets_timeout_cache[ASYNC_SELECT_TIMEOUT_CACHE_SIZE]; + +static int32_t async_select_get_socket_index(int32_t fd) +{ + int32_t index = -1; + + for (int32_t i = 0; i < ASYNC_SELECT_TIMEOUT_CACHE_SIZE; i++) { + if (async_select_sockets_timeout_cache[i].fd == fd) { + index = i; + break; + } + } + return index; +} + +static int32_t async_select_add_socket_to_cache(int32_t fd) +{ + int32_t index = -1; + for (int32_t i = 0; i < ASYNC_SELECT_TIMEOUT_CACHE_SIZE; i++) { + if (async_select_sockets_timeout_cache[i].fd == -1) { + async_select_sockets_timeout_cache[i].fd = fd; + index = i; + break; + } + } + + if (index == ASYNC_SELECT_TIMEOUT_CACHE_SIZE) { + LLNET_DEBUG_TRACE("async_select_add_socket: too many file descriptors in cache!\n"); + } + return index; +} + +void async_select_remove_socket_timeout_from_cache(int32_t fd) +{ + int32_t idx = async_select_get_socket_index(fd); + + // check if the file descriptor is valid + if (idx >= 0) { + async_select_sockets_timeout_cache[idx].fd = -1; + async_select_sockets_timeout_cache[idx].timeout = -1; + async_select_sockets_timeout_cache[idx].absolute_timeout = -1; + } else { + LLNET_DEBUG_TRACE("async_select_remove_socket_timeout_from_cache: invalid file descriptor(%d)!\n", fd); + } +} + +void async_select_init_socket_timeout_cache(void) +{ + for (int32_t i = 0; i < ASYNC_SELECT_TIMEOUT_CACHE_SIZE; i++) { + async_select_sockets_timeout_cache[i].fd = -1; + async_select_sockets_timeout_cache[i].timeout = -1; + async_select_sockets_timeout_cache[i].absolute_timeout = -1; + } +} + +int32_t async_select_get_socket_timeout_from_cache(int32_t fd) +{ + int32_t idx = async_select_get_socket_index(fd); + + // check if the file descriptor was found + if (idx >= 0) { + return async_select_sockets_timeout_cache[idx].timeout; + } else { + return -1; + } +} + +int64_t async_select_get_socket_absolute_timeout_from_cache(int32_t fd) +{ + int32_t idx = async_select_get_socket_index(fd); + + // check if the file descriptor was found + if (idx >= 0) { + return async_select_sockets_timeout_cache[idx].absolute_timeout; + } else { + return -1; + } +} + +void async_select_set_socket_timeout_in_cache(int32_t fd, int32_t timeout) +{ + int32_t idx = async_select_get_socket_index(fd); + + // check if the file descriptor was found + if (idx < 0) { + idx = async_select_add_socket_to_cache(fd); + } + + if (idx >= 0) { + async_select_sockets_timeout_cache[idx].timeout = timeout; + } +} + +int32_t async_select_set_socket_absolute_timeout_in_cache(int32_t fd, int64_t absolute_timeout) +{ + int32_t idx = async_select_get_socket_index(fd); + + // check if the file descriptor was found + if (idx < 0) { + idx = async_select_add_socket_to_cache(fd); + } + + if (idx >= 0) { + async_select_sockets_timeout_cache[idx].absolute_timeout = absolute_timeout; + } else { + return -1; + } + return 0; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/async_select_osal.c b/bsp/projects/microej/net/src/async_select_osal.c new file mode 100644 index 0000000..714f21b --- /dev/null +++ b/bsp/projects/microej/net/src/async_select_osal.c @@ -0,0 +1,108 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief Asynchronous network select implementation over OSAL API. + * @author MicroEJ Developer Team + * @version 2.3.1 + * @date 16 May 2022 + */ + +#include "async_select.h" +#include "async_select_configuration.h" +#include "osal.h" +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief Initializes the requests FIFOs. + * This function must be called prior to any call of async_select(). + * It can be called several times. + */ +extern void async_select_request_fifo_init(void); +/** + * @brief The entry point for the async_select task. + * This function must be called from a dedicated task. + */ +extern void async_select_task_main(void); + +/* + * See implementations for descriptions. + */ +void async_select_lock(void); +void async_select_unlock(void); +static int32_t async_select_start_task(void); + +/** + * @brief Stack of the async_select task. + */ +OSAL_task_stack_declare(async_select_task_stack, ASYNC_SELECT_TASK_STACK_SIZE); +/** + * @brief async_select OS task. + */ +static OSAL_task_handle_t async_select_task; +/** + * @brief Mutex used for critical sections. + */ +static OSAL_mutex_handle_t async_select_mutex; + +/** + * @brief Initialize the async_select component. This function must be called prior to any call of + * async_select(). + * + * @return 0 on success, -1 on failure. + */ +int32_t async_select_init(){ + int32_t res; + res = async_select_start_task(); + if(res == 0){ + async_select_request_fifo_init(); + } + return res; +} + +/** + * @brief Start RTOS task and init RTOS specific structures. + */ +static int32_t async_select_start_task(){ + OSAL_status_t status; + + status = OSAL_mutex_create(ASYNC_SELECT_MUTEX_NAME, &async_select_mutex); + + if(status == OSAL_OK){ + status = OSAL_task_create((OSAL_task_entry_point_t) async_select_task_main, ASYNC_SELECT_TASK_NAME, async_select_task_stack, ASYNC_SELECT_TASK_PRIORITY, NULL, &async_select_task); + } + + if(status == OSAL_OK){ + return 0; + } + else{ + return -1; + } +} + +/** + * @brief Enter critical section for the async_select component. + */ +void async_select_lock(void){ + OSAL_mutex_take(&async_select_mutex, OSAL_INFINITE_TIME); +} + +/** + * @brief Exit critical section for the async_select component. + */ +void async_select_unlock(void){ + OSAL_mutex_give(&async_select_mutex); +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/net/src/lwip_util.c b/bsp/projects/microej/net/src/lwip_util.c new file mode 100644 index 0000000..475b3fb --- /dev/null +++ b/bsp/projects/microej/net/src/lwip_util.c @@ -0,0 +1,432 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + * + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * @brief lwip_util implementation over LWIP and FreeRTOS. + * @author MicroEJ Developer Team + * @version 0.2.1 + * @date 3 August 2020 + */ + +#include +#include "lwip_util.h" +#include "LLNET_Common.h" + + +#include "ping.h" +#include "netif/ethernet.h" +#include "ethernetif.h" +#include "lwip/dhcp.h" +#include "lwip/init.h" +#include "lwip/ip_addr.h" +#include "lwip/netifapi.h" +#include "lwip/prot/dhcp.h" +#include "lwip/tcpip.h" +#include "lwip/sys.h" +#include "lwip/dns.h" + +#include "pin_mux.h" +#include "board.h" +#ifndef configMAC_ADDR +#include "fsl_silicon_id.h" +#endif +#include "fsl_phy.h" + +#include "fsl_enet.h" +#include "fsl_phylan8741.h" + +static TaskHandle_t dhcp_task_handle; + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Ethernet configuration. */ +phy_lan8741_resource_t g_phy_resource; +#define ENET_PHY_ADDRESS BOARD_ENET0_PHY_ADDRESS +#define ENET_PHY_OPS &phylan8741_ops +#define ENET_PHY_RESOURCE &g_phy_resource +#define ENET_CLOCK_FREQ CLOCK_GetCoreSysClkFreq() + +#define ETHERNETIF_INIT ethernetif0_init + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*Initialize physic etherner handler */ +static phy_handle_t phyHandle; + +#define MAX_DHCP_TRIES 4 +#define LWIP_DHCP_TASK_PRIORITY 1 + +/* DHCP process states */ +#define DHCP_START (uint8_t) 1 +#define DHCP_WAIT_ADDRESS (uint8_t) 2 +#define DHCP_ADDRESS_ASSIGNED (uint8_t) 3 +#define DHCP_TIMEOUT (uint8_t) 4 +#define DHCP_LINK_DOWN (uint8_t) 5 + +struct netif gnetif; +uint8_t DHCP_state; + +static uint8_t dhcp_sleeping = 1; + +/* variable used to notify that DNS servers list has changed */ +uint8_t dns_servers_list_updated = 1; + +static void ethernetif_static_ip_config(void); + +/** @brief Array holding all the network interface names at LwIP level. */ +static char lwip_netif[NUMB_OF_NETIF_TO_STORE][MAX_SIZE_OF_NETIF_NAME]; + +/** + * @brief Reset the network interface ip, netmask and gateway addresses to zero. + * @param netif: the network interface + * @retval None + */ +static void netif_addr_set_zero_ip4(struct netif* netif){ + ip_addr_set_zero_ip4(&netif->ip_addr); + ip_addr_set_zero_ip4(&netif->netmask); + ip_addr_set_zero_ip4(&netif->gw); +} + +/** + * @brief This function is called when the network interface is disconnected. + * @param netif: the network interface + * @retval None + */ +void netif_not_connected(struct netif *netif){ + netif_addr_set_zero_ip4(netif); + LLNET_DEBUG_TRACE("[INFO] The network cable is not connected \n"); +} + +/** + * @brief Notify the User about the nework interface config status + * @param netif: the network interface + * @retval None + */ +static void User_notification(struct netif *netif) +{ + int32_t dhcpConfEnabled = true; + if (netif_is_up(netif)) + { + if(dhcpConfEnabled) + { + /* Update DHCP state machine */ + DHCP_state = DHCP_START; + }else{ + // launch static Network Interface configuration + ethernetif_static_ip_config(); + } + } + else + { + netif_not_connected(netif); + if(dhcpConfEnabled) + { + /* Update DHCP state machine */ + DHCP_state = DHCP_LINK_DOWN; + } + } + +} + +static void MDIO_Init(void) +{ + (void)CLOCK_EnableClock(s_enetClock[ENET_GetInstance(ENET0)]); + ENET_SetSMI(ENET0, ENET_CLOCK_FREQ); +} + +static status_t MDIO_Write(uint8_t phyAddr, uint8_t regAddr, uint16_t data) +{ + return ENET_MDIOWrite(ENET0, phyAddr, regAddr, data); +} + +static status_t MDIO_Read(uint8_t phyAddr, uint8_t regAddr, uint16_t *pData) +{ + return ENET_MDIORead(ENET0, phyAddr, regAddr, pData); +} + +/** + * @brief Setup the network interface + * @param None + * @retval None + */ +static void Netif_Config(void) +{ + ip_addr_t ipaddr; + ip_addr_t netmask; + ip_addr_t gw; + + ip_addr_set_zero_ip4(&ipaddr); + ip_addr_set_zero_ip4(&netmask); + ip_addr_set_zero_ip4(&gw); + MDIO_Init(); + g_phy_resource.read = MDIO_Read; + g_phy_resource.write = MDIO_Write; + ethernetif_config_t enet_config = { + .phyHandle = &phyHandle, + .phyAddr = ENET_PHY_ADDRESS, + .phyOps = ENET_PHY_OPS, + .phyResource = ENET_PHY_RESOURCE, + .srcClockHz = ENET_CLOCK_FREQ, +#ifdef configMAC_ADDR + .macAddress = configMAC_ADDR, +#endif + }; +#ifndef configMAC_ADDR + /* Set special address for each chip. */ + (void)SILICONID_ConvertToMacAddr(&enet_config.macAddress); +#endif + + /* Add the network interface */ +#if NO_SYS + netifapi_netif_add(&gnetif, &ipaddr, &netmask, &gw, &enet_config, ETHERNETIF_INIT, &netif_input); +#else + netifapi_netif_add(&gnetif, &ipaddr, &netmask, &gw, &enet_config, ETHERNETIF_INIT, &tcpip_input); + +#endif + + /* Registers the default network interface */ + netifapi_netif_set_default(&gnetif); + netifapi_netif_set_up(netif_default); + /* Set the link callback function, this function is called on change of link status */ + //netif_set_link_callback(&gnetif, ethernetif_config); + User_notification(&gnetif); +} + +/* + * Retrieve static IP configuration of the default network interface and set + * IP parameters (Interface IP address, Netmask and Gateway IP address). + */ +static void ethernetif_static_ip_config() +{ + ip_addr_t ipaddr; + ip_addr_t netmask; + ip_addr_t gw; + ip_addr_t dnsaddr; + PRINTF("getting static address \n"); + // static IP configuration. Retrieve IP settings from user properties. + ipaddr.addr = 0; + netmask.addr = 0; + gw.addr = 0; + netif_set_addr(&gnetif, &ipaddr , &netmask, &gw); + LLNET_DEBUG_TRACE("[INFO] Static IP address assigned: %s\n", inet_ntoa(ipaddr.addr)); + + // set static DNS Host IP address. + if(DNS_MAX_SERVERS > 0) + { + char * static_dns_ip_addr = NULL; + if(static_dns_ip_addr != NULL) + { + dnsaddr.addr = inet_addr(static_dns_ip_addr); + dns_setserver(0, &dnsaddr); + // notify DNS servers IP address updated + dns_servers_list_updated = 1; + } + } +} + +/** + * @brief This function notify user about link status changement. + * @param netif: the network interface + * @retval None + */ +void ethernetif_notify_conn_changed(struct netif *netif) +{ + ip_addr_t ipaddr; + ip_addr_t netmask; + ip_addr_t gw; + int32_t dhcpConfEnabled = true; + + if(netif_is_link_up(netif)) + { + LLNET_DEBUG_TRACE("[INFO] The network cable is now connected \n"); + + if(dhcpConfEnabled) + { + /* Update DHCP state machine */ + DHCP_state = DHCP_START; + + netif_set_addr(netif, &ipaddr , &netmask, &gw); + + // resume DHCP thread + dhcp_sleeping = 0; + vTaskResume(dhcp_task_handle); + }else{ + // launch static Network Interface configuration + ethernetif_static_ip_config(); + } + + /* When the netif is fully configured this function must be called.*/ + netif_set_up(netif); + } + else + { + if(dhcpConfEnabled){ + /* Update DHCP state machine */ + DHCP_state = DHCP_LINK_DOWN; + } + + /* When the netif link is down this function must be called.*/ + netif_set_down(netif); + + netif_not_connected(netif); + } +} + +static void DHCP_thread(void const * argument) +{ + struct netif *netif = (struct netif *) argument; + uint32_t IPaddress; + + for (;;) + { + // check if DHCP thread has to suspend + if(dhcp_sleeping == 1){ + vTaskDelete(dhcp_task_handle); + } + + switch (DHCP_state) + { + case DHCP_START: + { + netif_addr_set_zero_ip4(netif); + IPaddress = 0; + netifapi_dhcp_start(netif); + DHCP_state = DHCP_WAIT_ADDRESS; + LLNET_DEBUG_TRACE("[INFO] DHCP started\n"); + } + break; + + case DHCP_WAIT_ADDRESS: + { + /* Read the new IP address */ + IPaddress = netif->ip_addr.addr; + if (IPaddress != 0) + { + DHCP_state = DHCP_ADDRESS_ASSIGNED; + + /* Stop DHCP */ +#if LWIP_VERSION_MAJOR == 1 + dhcp_stop(netif); +#elif LWIP_VERSION_MAJOR == 2 + // LwIP version 2 onward clears existing IP address if dhcp is stopped. + //dhcp_stop(netif); +#else + #error "Invalid LWIP version (LWIP_VERSION_MAJOR)." +#endif + dhcp_sleeping = 1; + + LLNET_DEBUG_TRACE("[INFO] DHCP address assigned: %s\n", inet_ntoa(IPaddress)); + if(1) + { + ip_addr_t dnsaddr; + if(DNS_MAX_SERVERS > 0) + { + char * static_dns_ip_addr = NULL; + if(static_dns_ip_addr != NULL) + { + dnsaddr.addr = inet_addr(static_dns_ip_addr); + dns_setserver(0, &dnsaddr); + } + } + } + + // notify DNS servers IP address updated + dns_servers_list_updated = 1; + } + else + { +#if LWIP_VERSION_MAJOR == 1 + + struct dhcp *dhcp = netif->dhcp; + +#elif LWIP_VERSION_MAJOR == 2 + struct dhcp *dhcp = (struct dhcp*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP); + +#else + + #error "Invalid LWIP version (LWIP_VERSION_MAJOR)." + +#endif + + /* DHCP timeout */ + if (dhcp->tries > MAX_DHCP_TRIES) + { + DHCP_state = DHCP_TIMEOUT; + + /* Stop DHCP */ + dhcp_stop(netif); + dhcp_sleeping = 1; + + LLNET_DEBUG_TRACE("[INFO] DHCP timeout\n"); + } + } + } + break; + + default: break; + } + } +} + +/** + * Network initialization. Start network interfaces and configure it. + * @return 0 if no error occurred, error code otherwise. + */ +int32_t llnet_lwip_init(void) +{ + PRINTF ("network initialize \n"); + int32_t dhcpConfEnabled = true; + /* Initialize the LwIP TCP/IP stack */ + tcpip_init(NULL, NULL); + /* Configure the Network interface */ + Netif_Config(); + if(dhcpConfEnabled) + { + /* Start DHCPClient */ + dhcp_sleeping = 0; +#if defined(__GNUC__) + xTaskCreate((TaskFunction_t)DHCP_thread, "DHCP", configMINIMAL_STACK_SIZE * 5, &gnetif, LWIP_DHCP_TASK_PRIORITY, &dhcp_task_handle); +#else + xTaskCreate((TaskFunction_t)DHCP_thread, "DHCP", configMINIMAL_STACK_SIZE*2, &gnetif, LWIP_DHCP_TASK_PRIORITY, &dhcp_task_handle); +#endif + } + return 0; +} + +void set_lwip_netif_name(int32_t id, char *netif_name) +{ + strcpy(lwip_netif[id], netif_name); +} + +char *get_lwip_netif_name(int32_t id) +{ + return lwip_netif[id]; +} + +struct netif* getNetworkInterface(int8_t* name) +{ + char *llnet_netif[] = LLNET_NETIF_NAMES; + for (int32_t netif_idx = 0; netif_idx < (sizeof(llnet_netif) / sizeof(llnet_netif[0])); netif_idx++) { + if (strcmp((char *)name, llnet_netif[netif_idx]) == 0) { + // the same interface name at LLNET level can have different names at platform level + // so, keep trying to find the lwip level interface until one is found or until we exhaust the list + struct netif *ret = netif_find(lwip_netif[netif_idx]); + if (ret) { + return ret; + } + } + } + return NULL; +} diff --git a/bsp/projects/microej/scripts/Jlink.cmd b/bsp/projects/microej/scripts/Jlink.cmd new file mode 100644 index 0000000..a6a4b1e --- /dev/null +++ b/bsp/projects/microej/scripts/Jlink.cmd @@ -0,0 +1,10 @@ +// Copyright 2022 MicroEJ Corp. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found with this software. + +r +loadbin application.bin,0x10000000 +savebin out.bin 0x10000000 10 +h +r +g +qc diff --git a/bsp/projects/microej/scripts/build.bat b/bsp/projects/microej/scripts/build.bat new file mode 100644 index 0000000..c24bf42 --- /dev/null +++ b/bsp/projects/microej/scripts/build.bat @@ -0,0 +1,20 @@ +REM 'build.bat' implementation for GCC GnuToolChain + +REM 'build.bat' is responsible for producing the executable file +REM then copying this executable file to the current directory where it has been executed to a file named 'application.out' + +SET CURRENT_DIRECTORY=%CD% + +cd "%~dp0..\..\nxpvee-ui\sdk_makefile" +make RELEASE=1 CMAKE_OPTS="-DENABLE_NET=1 -DENABLE_SEC=1" +IF %ERRORLEVEL% NEQ 0 ( + exit /B %ERRORLEVEL% +) + +copy /Y ..\armgcc\release\nxpvee_ui.elf %CURRENT_DIRECTORY%\application.out +copy /Y ..\armgcc\release\nxpvee_ui.hex %CURRENT_DIRECTORY%\application.hex +copy /Y ..\armgcc\release\nxpvee_ui.bin %CURRENT_DIRECTORY%\application.bin + +copy /Y ..\armgcc\release\nxpvee_ui.bin %~dp0\application.bin + +cd "%CURRENT_DIRECTORY%" diff --git a/bsp/projects/microej/scripts/build.sh b/bsp/projects/microej/scripts/build.sh new file mode 100755 index 0000000..4976884 --- /dev/null +++ b/bsp/projects/microej/scripts/build.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -euo pipefail + +# Defaults to ARMGCC +echo "TEST TYPE ${TEST_TYPE:=ARMGCC}" + +CURRENT_DIRECTORY=$(pwd) + +# go to parent directory of script's location +SCRIPT_DIR=$(dirname "$(realpath "$0")") +cd "$SCRIPT_DIR/../../nxpvee-ui/sdk_makefile" || exit 1 + +# shell scripts may have lost their execution flag is they come from a zip +chmod -f +x $SCRIPT_DIR/../../nxpvee-ui/armgcc/*.sh || true + +make RELEASE=1 CMAKE_OPTS="-DENABLE_NET=1 -DENABLE_SEC=1" || exit 2 + +cp ../armgcc/release/nxpvee_ui.elf "$CURRENT_DIRECTORY"/application.out || exit 3 +cp ../armgcc/release/nxpvee_ui.hex "$CURRENT_DIRECTORY"/application.hex || exit 3 +cp ../armgcc/release/nxpvee_ui.bin "$CURRENT_DIRECTORY"/application.bin || exit 3 + +cd "$CURRENT_DIRECTORY" || exit 4 diff --git a/bsp/projects/microej/scripts/run.bat b/bsp/projects/microej/scripts/run.bat new file mode 100644 index 0000000..879c9f0 --- /dev/null +++ b/bsp/projects/microej/scripts/run.bat @@ -0,0 +1,20 @@ +REM 'run.bat' implementation for GCC workbench, using Jlink. + +SET CURRENT_DIRECTORY=%CD% +SET MAKEFILE_DIR="%~dp0\..\..\nxpvee-ui\sdk_makefile" + +CD %MAKEFILE_DIR% + +IF %ERRORLEVEL% NEQ 0 ( + ECHO "Can not open %MAKEFILE_DIR%" + EXIT /B %ERRORLEVEL% +) + +make RELEASE=1 flash_cmsisdap + +IF %ERRORLEVEL% NEQ 0 ( + ECHO "Failed to flash the board" + EXIT /B %ERRORLEVEL% +) + +cd "%CURRENT_DIRECTORY%" diff --git a/bsp/projects/microej/scripts/run.sh b/bsp/projects/microej/scripts/run.sh new file mode 100755 index 0000000..69682a5 --- /dev/null +++ b/bsp/projects/microej/scripts/run.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -euo pipefail + +# Defaults to ARMGCC +echo "TEST TYPE ${TEST_TYPE:=ARMGCC}" + +CURRENT_DIRECTORY=$(pwd) + +# go to directory of script's location +SCRIPT_DIR=$(dirname "$(realpath "$0")") +cd "${SCRIPT_DIR}/../../nxpvee-ui/sdk_makefile/" + +# shell scripts may have lost their execution flag is they come from a zip +chmod -f +x $SCRIPT_DIR/../../nxpvee-ui/armgcc/*.sh || true + +make RELEASE=1 flash_cmsisdap + +cd "$CURRENT_DIRECTORY" diff --git a/bsp/projects/microej/scripts/set_project_env.bat b/bsp/projects/microej/scripts/set_project_env.bat new file mode 100644 index 0000000..563c2d5 --- /dev/null +++ b/bsp/projects/microej/scripts/set_project_env.bat @@ -0,0 +1,36 @@ +@echo off + +REM Copyright 2021-2022 MicroEJ Corp. All rights reserved. +REM Use of this source code is governed by a BSD-style license that can be found with this software. + +REM 'set_project_env.bat' implementation for GCC workbench, using JLINK + +REM 'set_project_env' is responsible for +REM - checking the availability of required environment variables +REM - setting project local variables for 'build.bat' and 'run.bat' + +REM Required Environment Variable +REM JLink installation directory +REM JLINK_INSTALLATION_DIR +REM GNU ToolChain installation directory +REM GNUCC_93x_INSTALLATION_DIR + +IF "%JLINK_INSTALLATION_DIR%" == "" ( + ECHO Please set the environment variable 'JLINK_INSTALLATION_DIR' + exit /B -1 +) + +IF "%GNUCC_93x_INSTALLATION_DIR%" == "" ( + ECHO Please set the environment variable 'GNUCC_93x_INSTALLATION_DIR' + exit /B -1 +) + +SET PROJECT_DIR=%~dp0 +SET PROJECT_NAME=application + +ECHO JLINK_INSTALLATION_DIR=%JLINK_INSTALLATION_DIR% +ECHO GNUCC_93x_INSTALLATION_DIR=%JLINK_INSTALLATION_DIR% + +SET PATH=%PATH%;%GNUCC_93x_INSTALLATION_DIR% + +exit /B 0 \ No newline at end of file diff --git a/bsp/projects/microej/security/inc/LLSEC_configuration.h b/bsp/projects/microej/security/inc/LLSEC_configuration.h new file mode 100644 index 0000000..c02586d --- /dev/null +++ b/bsp/projects/microej/security/inc/LLSEC_configuration.h @@ -0,0 +1,24 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief Security natives configuration. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include "mbedtls/platform.h" + +#define LLSEC_calloc mbedtls_calloc +#define LLSEC_free mbedtls_free + +/* +* Used for private and public key generation +*/ +#define LLSEC_PRIVATE_KEY_LOCAL_BUFFER_SIZE 3072 +#define LLSEC_PUBLIC_KEY_LOCAL_BUFFER_SIZE 3072 diff --git a/bsp/projects/microej/security/inc/LLSEC_mbedtls.h b/bsp/projects/microej/security/inc/LLSEC_mbedtls.h new file mode 100644 index 0000000..0136448 --- /dev/null +++ b/bsp/projects/microej/security/inc/LLSEC_mbedtls.h @@ -0,0 +1,38 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief Security natives mbedtls structs. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#ifndef LLSEC_MBEDTLS +#define LLSEC_MBEDTLS + +#include "mbedtls/pk.h" + +typedef enum { + TYPE_RSA = 6, //EVP_PKEY_RSA, + TYPE_ECDSA = 408, //EVP_PKEY_EC, +} LLSEC_pub_key_type; + +/*key must be mbedtls_rsa_context or mbedtls_ecdsa_context TYPE*/ +typedef struct { + LLSEC_pub_key_type type; + char *key; /*mbedtls_rsa_context or mbedtls_ecdsa_context*/ +} LLSEC_priv_key; + +typedef struct { + LLSEC_pub_key_type type; + char *key; /*mbedtls_rsa_context or mbedtls_ecdsa_context*/ +} LLSEC_pub_key; + +extern char *llsec_gen_random_str_internal(int length); + +#endif /* LLSEC_MBEDTLS */ diff --git a/bsp/projects/microej/security/microej_security.cmake b/bsp/projects/microej/security/microej_security.cmake new file mode 100644 index 0000000..571e7a8 --- /dev/null +++ b/bsp/projects/microej/security/microej_security.cmake @@ -0,0 +1,16 @@ +include_guard() +message("microej/security component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_CIPHER_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_DIGEST_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_KEY_FACTORY_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_KEY_PAIR_GENERATOR_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_MAC_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_PRIVATE_KEY_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_PUBLIC_KEY_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_RANDOM_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_SIG_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLSEC_X509_CERT_impl.c +) +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) diff --git a/bsp/projects/microej/security/src/LLSEC_CIPHER_impl.c b/bsp/projects/microej/security/src/LLSEC_CIPHER_impl.c new file mode 100644 index 0000000..e5da840 --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_CIPHER_impl.c @@ -0,0 +1,409 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + include mbedtls +*/ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +// cppcheck-suppress preprocessorErrorDirective // macro include +#include MBEDTLS_CONFIG_FILE +#endif +#include "mbedtls/aes.h" +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" + +#define LLSEC_CIPHER_SUCCESS 0 +#define LLSEC_CIPHER_ERROR -1 +#define AES_CBC_BLOCK_BITS 128u +#define AES_CBC_BLOCK_BYTES AES_CBC_BLOCK_BITS / 8u + +//#define LLSEC_CIPHER_DEBUG + +#ifdef LLSEC_CIPHER_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_CIPHER_DEBUG_TRACE(...) (void)printf(__VA_ARGS__) +#else +#define LLSEC_CIPHER_DEBUG_TRACE(...) ((void)0) +#endif + +/** + * Cipher init function type + */ +typedef int (*LLSEC_CIPHER_init)(int32_t transformation_id, void** native_id, uint8_t is_decrypting, uint8_t* key, int32_t key_length, uint8_t* iv, int32_t iv_length); +typedef int (*LLSEC_CIPHER_decrypt)(void* native_id, uint8_t* buffer, int32_t buffer_length, uint8_t* output); +typedef int (*LLSEC_CIPHER_encrypt)(void* native_id, uint8_t* buffer, int32_t buffer_length, uint8_t* output); +typedef void (*LLSEC_CIPHER_close)(void* native_id); + +typedef struct { + char* name; // the name of the transformation + LLSEC_CIPHER_init init; + LLSEC_CIPHER_decrypt decrypt; + LLSEC_CIPHER_encrypt encrypt; + LLSEC_CIPHER_close close; + LLSEC_CIPHER_transformation_desc description; +} LLSEC_CIPHER_transformation; + +typedef struct { + LLSEC_CIPHER_transformation* transformation; + mbedtls_aes_context mbedtls_ctx; + int32_t iv_length; + uint8_t iv[1]; +} LLSEC_CIPHER_ctx; + +static int LLSEC_CIPHER_aescbc_init(int32_t transformation_id, void** native_id, uint8_t is_decrypting, uint8_t* key, int32_t key_length, uint8_t* iv, int32_t iv_length); +static int mbedtls_cipher_decrypt(void* native_id, uint8_t* buffer, int32_t buffer_length, uint8_t* output); +static int mbedtls_cipher_encrypt(void* native_id, uint8_t* buffer, int32_t buffer_length, uint8_t* output); +static void mbedtls_cipher_close(void* native_id); + +// cppcheck-suppress misra-c2012-8.9 // Define here for code readability even if it called once in this file. +static LLSEC_CIPHER_transformation available_transformations[1] = { + { + .name = "AES/CBC/NoPadding", + .init = LLSEC_CIPHER_aescbc_init, + .decrypt = mbedtls_cipher_decrypt, + .encrypt = mbedtls_cipher_encrypt, + .close = mbedtls_cipher_close, + { + .block_size = AES_CBC_BLOCK_BYTES, + .unit_bytes = AES_CBC_BLOCK_BYTES, + .cipher_mode = CBC_MODE, + }, + } +}; + + +static int LLSEC_CIPHER_aescbc_init(int32_t transformation_id, void** native_id, uint8_t is_decrypting, uint8_t* key, int32_t key_length, uint8_t* iv, int32_t iv_length) +{ + LLSEC_CIPHER_ctx* p_cipher_ctx; + LLSEC_CIPHER_DEBUG_TRACE("%s %d\n", __func__, is_decrypting); + + int return_code = LLSEC_CIPHER_SUCCESS; + p_cipher_ctx = LLSEC_calloc(1, (int32_t)sizeof(LLSEC_CIPHER_ctx) - 1 + iv_length); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + p_cipher_ctx->transformation = (LLSEC_CIPHER_transformation*) transformation_id; + mbedtls_aes_init(&p_cipher_ctx->mbedtls_ctx); + + if (is_decrypting != (uint8_t) 0) { + return_code = mbedtls_aes_setkey_dec(&p_cipher_ctx->mbedtls_ctx, key, key_length * 8); + } else { + return_code = mbedtls_aes_setkey_enc(&p_cipher_ctx->mbedtls_ctx, key, key_length * 8); + } + + if(return_code != LLSEC_CIPHER_SUCCESS) { + return_code = LLSEC_CIPHER_ERROR; + } else { + p_cipher_ctx->iv_length = iv_length; + (void) memcpy(p_cipher_ctx->iv, iv, iv_length); + *native_id = p_cipher_ctx; + } + return return_code; +} + +static int mbedtls_cipher_decrypt(void* native_id, uint8_t* buffer, int32_t buffer_length, uint8_t* output) +{ + // cppcheck-suppress misra-c2012-11.5 // Abstract data type for SNI usage + LLSEC_CIPHER_ctx* p_cipher_ctx = (LLSEC_CIPHER_ctx*)native_id; + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + return mbedtls_aes_crypt_cbc(&p_cipher_ctx->mbedtls_ctx, MBEDTLS_AES_DECRYPT, buffer_length, + p_cipher_ctx->iv, buffer, output); +} + +static int mbedtls_cipher_encrypt(void* native_id, uint8_t* buffer, int32_t buffer_length, uint8_t* output) +{ + // cppcheck-suppress misra-c2012-11.5 // Abstract data type for SNI usage + LLSEC_CIPHER_ctx* p_cipher_ctx = (LLSEC_CIPHER_ctx*)native_id; + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + return mbedtls_aes_crypt_cbc(&p_cipher_ctx->mbedtls_ctx, MBEDTLS_AES_ENCRYPT, buffer_length, + p_cipher_ctx->iv, buffer, output); +} + +static void mbedtls_cipher_close(void* native_id) +{ + LLSEC_CIPHER_DEBUG_TRACE("%s native_id:%p\n", __func__, native_id); + LLSEC_free(native_id); +} + +/** + * @brief Gets for the given transformation the cipher description. + *

+ * transformation_desc must be filled-in with: + *

    + *
  • [0-3]: native transformation ID
  • + *
  • [4-7]: blockSize: the block size (in bytes), or 0 if the underlying algorithm is not a block cipher
  • + *
  • [8-11]: unitBytes: unit size (number of input bytes that can be processed at a time)
  • + *
  • [12-15]: cipherMode: one of the *_MODE values defined in {@link AbstractCipher}
  • + *
+ * + * @param transformation_name[in] Null terminated string that describes the transformation. + * @param transformation_desc[out] Description of the cipher. + * + * @return The transformation ID on success or -1 on error. + * + * @warning transformation_name must not be used outside of the VM task or saved. + */ +int32_t LLSEC_CIPHER_IMPL_get_transformation_description(uint8_t* transformation_name, LLSEC_CIPHER_transformation_desc* transformation_desc) +{ + int32_t return_code = LLSEC_CIPHER_SUCCESS; + LLSEC_CIPHER_DEBUG_TRACE("%s transformation_name %s\n", __func__, transformation_name); + int32_t nb_transformations = sizeof(available_transformations) / sizeof(LLSEC_CIPHER_transformation); + LLSEC_CIPHER_transformation* transformation = &available_transformations[0]; + + while (--nb_transformations >= 0) { + if (strcmp((const char*)transformation_name, transformation->name) == 0) { + (void) memcpy(transformation_desc, &(transformation->description), sizeof(LLSEC_CIPHER_transformation_desc)); + break; + } + transformation++; + } + + if (nb_transformations >= 0) + { + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + return_code = (int32_t)transformation; + } else { + return_code = LLSEC_CIPHER_ERROR; + } + return return_code; +} + +/** + * @brief Returns the number of bytes that are buffered internally inside the given cipher. + * + * @param[in] nativeTransformationId The transformation ID. + * @param[in] nativeId The resource's native ID. + * + * @return The length of the buffer. + */ +int32_t LLSEC_CIPHER_IMPL_get_buffered_length(int32_t nativeTransformationId, int32_t nativeId) +{ + (void) nativeTransformationId; // Unused input parameter + (void) nativeId; // Unused input parameter + return LLSEC_CIPHER_SUCCESS; +} + +/** + * @brief Gets the initialization vector. + * + * @param[in] transformation_id The transformation ID. + * @param[in] native_id The resource's native ID. + * @param[out] iv The initialization vector of the cipher. + * @param[out] iv_length The initialization vector size. + * + * @note Throws NativeException on error. + * + * @warning iv must not be used outside of the VM task or saved. + */ +void LLSEC_CIPHER_IMPL_get_IV(int32_t transformation_id, int32_t native_id, uint8_t* iv, int32_t iv_length) +{ + (void) transformation_id; // Unused input parameter + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_CIPHER_ctx* p_cipher_ctx = (LLSEC_CIPHER_ctx*)native_id; + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + (void) memcpy(iv, p_cipher_ctx->iv, iv_length); +} + +/** + * @brief Gets the length of the initialized vector. + * + * @param[in] transformation_id The transformation ID. + * @param[in] native_id The resource's native ID. + * + * @return The length of the IV, -1 if there is no IV. + */ +int32_t LLSEC_CIPHER_IMPL_get_IV_length(int32_t transformation_id, int32_t native_id) +{ + (void) transformation_id; // Unused input parameter + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_CIPHER_ctx* p_cipher_ctx = (LLSEC_CIPHER_ctx*)native_id; + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + return p_cipher_ctx->iv_length; +} + +/** + * @brief Initializes a Cipher resource. + * + * @param[in] tranformation_id The transformation ID. + * @param[in] is_decrypting '1' for decrypting, '0' for encryting. + * @param[in] key The key. + * @param[in] key_length The key size. + * @param[in] iv The initialization vector. + * @param[in] iv_length The initialization vector size. + * + * @return The nativeId of the newly initialized resource. + * + * @note Throws NativeException on error. + * + * @warning key must not be used outside of the VM task or saved. + * @warning iv must not be used outside of the VM task or saved. + */ +int32_t LLSEC_CIPHER_IMPL_init(int32_t transformation_id, uint8_t is_decrypting, uint8_t* key, int32_t key_length, uint8_t* iv, int32_t iv_length) +{ + int32_t return_code = LLSEC_CIPHER_SUCCESS; + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + void* native_id = NULL; + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_CIPHER_transformation* transformation = (LLSEC_CIPHER_transformation*)transformation_id; + + if (iv_length <= 0) { + SNI_throwNativeException(iv_length, "LLSEC_CIPHER_IMPL_init invalid iv length"); + return_code = LLSEC_CIPHER_ERROR; + } + + if (return_code == LLSEC_CIPHER_SUCCESS) { + return_code = transformation->init(transformation_id, (void**)&native_id, is_decrypting, key, key_length, iv, iv_length); + + if (return_code != LLSEC_CIPHER_SUCCESS) { + SNI_throwNativeException(return_code, "LLSEC_CIPHER_IMPL_init failed"); + return_code = LLSEC_CIPHER_ERROR; + } + } + + if (return_code == LLSEC_CIPHER_SUCCESS) { + // register SNI native resource + if (SNI_registerResource(native_id, transformation->close, NULL) != SNI_OK) { + SNI_throwNativeException(LLSEC_CIPHER_ERROR, "Can't register SNI native resource"); + transformation->close((void*)native_id); + return_code = LLSEC_CIPHER_ERROR; + } + } + + if (return_code == LLSEC_CIPHER_SUCCESS){ + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (int32_t)(native_id); + } + + return return_code; +} + +/** + * @brief Decrypts the message contained in buffer. + * + * @param[in] transformation_id The transformation ID. + * @param[in] native_id The resource's native ID. + * @param[in] buffer The buffer containing the message to decrypt. + * @param[in] buffer_offset The buffer offset. + * @param[in] buffer_length The buffer length. + * @param[out] output The output buffer containing the plaintext message. + * @param[out] output_offset The output offset. + * + * @return The length of the buffer. + * + * @note Throws NativeException on error. + * + * @warning buffer must not be used outside of the VM task or saved. + * @warning output must not be used outside of the VM task or saved. + */ +int32_t LLSEC_CIPHER_IMPL_decrypt(int32_t transformation_id, int32_t native_id, uint8_t* buffer, int32_t buffer_offset, int32_t buffer_length, uint8_t* output, int32_t output_offset) +{ + int32_t return_code = 0; + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_CIPHER_transformation* transformation = (LLSEC_CIPHER_transformation*)transformation_id; + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + int returnCode = transformation->decrypt((void*)native_id, &buffer[buffer_offset], buffer_length, &output[output_offset]); + if (returnCode != LLSEC_CIPHER_SUCCESS) { + SNI_throwNativeException(returnCode, "LLSEC_CIPHER_IMPL_decrypt failed"); + return_code = LLSEC_CIPHER_ERROR; + } else { + return_code = buffer_length; + } + return return_code; +} + +/** + * @brief Encrypts the message contained in buffer. + * + * @param[in] transformation_id The transformation ID. + * @param[in] native_id The resource's native ID. + * @param[in] buffer The buffer containing the plaintext message to encrypt. + * @param[in] buffer_offset The buffer offset. + * @param[in] buffer_length The buffer length. + * @param[out] output The output buffer containing the encrypted message. + * @param[in] output_offset The output offset. + * + * @return The length of the buffer. + * + * @note Throws NativeException on error. + * + * @warning buffer must not be used outside of the VM task or saved. + * @warning output must not be used outside of the VM task or saved. + */ +int32_t LLSEC_CIPHER_IMPL_encrypt(int32_t transformation_id, int32_t native_id, uint8_t* buffer, int32_t buffer_offset, int32_t buffer_length, uint8_t* output, int32_t output_offset) +{ + int32_t return_code = 0; + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_CIPHER_transformation* transformation = (LLSEC_CIPHER_transformation*)transformation_id; + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + int returnCode = transformation->encrypt((void*)native_id, &buffer[buffer_offset], buffer_length, &output[output_offset]); + if (returnCode != LLSEC_CIPHER_SUCCESS) { + SNI_throwNativeException(returnCode, "LLSEC_CIPHER_IMPL_encrypt failed"); + return_code = LLSEC_CIPHER_ERROR; + } else { + return_code = buffer_length; + } + return return_code; +} + +/** + * @brief Closes the resource related to the native ID. + * + * @param[in] transformation_id The transformation ID. + * @param[in] native_id The resource's native ID. + * + * @note Throws NativeException on error. + */ +void LLSEC_CIPHER_IMPL_close(int32_t transformation_id, int32_t native_id) +{ + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_CIPHER_transformation* transformation = (LLSEC_CIPHER_transformation*)transformation_id; + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + transformation->close((void*)native_id); + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + if (SNI_unregisterResource((void*)native_id, (SNI_closeFunction)transformation->close) != SNI_OK) { + SNI_throwNativeException(LLSEC_CIPHER_ERROR, "Can't unregister SNI native resource"); + } + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); +} + +/** + * @brief Gets the id of the native close function. + * @param[in] transformation_id The transformation ID. + * + * @return the id of the static native close function. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_CIPHER_IMPL_get_close_id(int32_t transformation_id) +{ + LLSEC_CIPHER_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_CIPHER_transformation* transformation = (LLSEC_CIPHER_transformation*)transformation_id; + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + return (int32_t)transformation->close; +} diff --git a/bsp/projects/microej/security/src/LLSEC_DIGEST_impl.c b/bsp/projects/microej/security/src/LLSEC_DIGEST_impl.c new file mode 100644 index 0000000..ae9ee09 --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_DIGEST_impl.c @@ -0,0 +1,441 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "mbedtls/platform.h" +#include "mbedtls/md.h" + +#define LLSEC_DIGEST_SUCCESS 0 +#define LLSEC_DIGEST_ERROR -1 + +#define MD5_DIGEST_LENGTH 16 +#define SHA1_DIGEST_LENGTH 20 +#define SHA256_DIGEST_LENGTH 32 +#define SHA512_DIGEST_LENGTH 64 + +//#define LLSEC_DIGEST_DEBUG + +#ifdef LLSEC_DIGEST_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include "fsl_debug_console.h" +#define LLSEC_DIGEST_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_DIGEST_DEBUG_TRACE(...) ((void)0) +#endif + +typedef int (*LLSEC_DIGEST_init)(void** native_id); +typedef int (*LLSEC_DIGEST_update)(void* native_id, uint8_t* buffer, int32_t buffer_length); +typedef int (*LLSEC_DIGEST_digest)(void* native_id, uint8_t* out, int32_t* out_length); +typedef void (*LLSEC_DIGEST_close)(void* native_id); + +/* + * LL-API related functions & struct + */ +typedef struct { + char* name; + LLSEC_DIGEST_init init; + LLSEC_DIGEST_update update; + LLSEC_DIGEST_digest digest; + LLSEC_DIGEST_close close; + LLSEC_DIGEST_algorithm_desc description; +} LLSEC_DIGEST_algorithm; + +static int mbedtls_digest_update(void* native_id, uint8_t* buffer, int32_t buffer_length); +static int mbedtls_digest_digest(void* native_id, uint8_t* out, int32_t* out_length); +static int LLSEC_DIGEST_MD5_init(void** native_id); +static int LLSEC_DIGEST_SHA1_init(void** native_id); +static int LLSEC_DIGEST_SHA256_init(void** native_id); +static int LLSEC_DIGEST_SHA512_init(void** native_id); +static void mbedtls_digest_close(void* native_id); + +// cppcheck-suppress misra-c2012-8.9 // Define here for code readability even if it called once in this file. +static LLSEC_DIGEST_algorithm available_digest_algorithms[4] = { + { + .name = "MD5", + .init = LLSEC_DIGEST_MD5_init, + .update = mbedtls_digest_update, + .digest = mbedtls_digest_digest, + .close = mbedtls_digest_close, + { + .digest_length = MD5_DIGEST_LENGTH + } + }, + { + .name = "SHA-1", + .init = LLSEC_DIGEST_SHA1_init, + .update = mbedtls_digest_update, + .digest = mbedtls_digest_digest, + .close = mbedtls_digest_close, + { + .digest_length = SHA1_DIGEST_LENGTH + } + }, + { + .name = "SHA-256", + .init = LLSEC_DIGEST_SHA256_init, + .update = mbedtls_digest_update, + .digest = mbedtls_digest_digest, + .close = mbedtls_digest_close, + { + .digest_length = SHA256_DIGEST_LENGTH + } + }, + { + .name = "SHA-512", + .init = LLSEC_DIGEST_SHA512_init, + .update = mbedtls_digest_update, + .digest = mbedtls_digest_digest, + .close = mbedtls_digest_close, + { + .digest_length = SHA512_DIGEST_LENGTH + } + } +}; + +/* + * Generic mbedtls function + */ +static int mbedtls_digest_update(void* native_id, uint8_t* buffer, int32_t buffer_length) +{ + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + + mbedtls_md_context_t* md_ctx = (mbedtls_md_context_t*)native_id; + int rc = mbedtls_md_update(md_ctx, buffer, buffer_length); + return rc; +} + +static int mbedtls_digest_digest(void* native_id, uint8_t* out, int32_t* out_length) +{ + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + + mbedtls_md_context_t* md_ctx = (mbedtls_md_context_t*)native_id; + int rc = mbedtls_md_finish(md_ctx, out); + + if (rc == 0) { + *out_length = strlen((char*)out); + } + + return rc; +} + +static void mbedtls_digest_close(void* native_id) +{ + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + + mbedtls_md_context_t* md_ctx = (mbedtls_md_context_t*)native_id; + + /* Memory deallocation */ + mbedtls_md_free(md_ctx); +} + +/* + * Specific md5 function + */ +static int LLSEC_DIGEST_MD5_init(void** native_id) +{ + int return_code = LLSEC_DIGEST_SUCCESS; + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + + mbedtls_md_context_t* md_ctx = mbedtls_calloc(1, sizeof(mbedtls_md_context_t)); + if (md_ctx == NULL) { + return_code = LLSEC_DIGEST_ERROR; + } + + if (return_code == LLSEC_DIGEST_SUCCESS){ + mbedtls_md_init(md_ctx); + + return_code = mbedtls_md_setup(md_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_MD5), 0); + if (return_code != LLSEC_DIGEST_SUCCESS) { + mbedtls_md_free(md_ctx); + } + } + + if (return_code == LLSEC_DIGEST_SUCCESS){ + return_code = mbedtls_md_starts(md_ctx); + if (return_code != LLSEC_DIGEST_SUCCESS) { + mbedtls_md_free(md_ctx); + } else { + *native_id = md_ctx; + } + } + return return_code; +} + +/* + * Specific sha-1 function + */ +static int LLSEC_DIGEST_SHA1_init(void** native_id) +{ + int return_code = LLSEC_DIGEST_SUCCESS; + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + + mbedtls_md_context_t* md_ctx = mbedtls_calloc(1, sizeof(mbedtls_md_context_t)); + if (md_ctx == NULL) { + return_code = LLSEC_DIGEST_ERROR; + } + + if (return_code == LLSEC_DIGEST_SUCCESS){ + mbedtls_md_init(md_ctx); + + return_code = mbedtls_md_setup(md_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 0); + if (return_code != LLSEC_DIGEST_SUCCESS) { + mbedtls_md_free(md_ctx); + } + } + + if (return_code == LLSEC_DIGEST_SUCCESS){ + return_code = mbedtls_md_starts(md_ctx); + if (return_code != LLSEC_DIGEST_SUCCESS) { + mbedtls_md_free(md_ctx); + } else { + *native_id = md_ctx; + } + } + return return_code; +} + +/* + * Specific sha-256 function + */ +static int LLSEC_DIGEST_SHA256_init(void** native_id) +{ + int return_code = LLSEC_DIGEST_SUCCESS; + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + + mbedtls_md_context_t* md_ctx = mbedtls_calloc(1, sizeof(mbedtls_md_context_t)); + if (md_ctx == NULL) { + return_code = LLSEC_DIGEST_ERROR; + } + + if (return_code == LLSEC_DIGEST_SUCCESS){ + mbedtls_md_init(md_ctx); + + return_code = mbedtls_md_setup(md_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 0); + if (return_code != LLSEC_DIGEST_SUCCESS) { + mbedtls_md_free(md_ctx); + } + } + + if (return_code == LLSEC_DIGEST_SUCCESS){ + return_code = mbedtls_md_starts(md_ctx); + if (return_code != LLSEC_DIGEST_SUCCESS) { + mbedtls_md_free(md_ctx); + } else { + *native_id = md_ctx; + } + } + return return_code; +} + +/* + * Specific sha-512 function + */ +static int LLSEC_DIGEST_SHA512_init(void** native_id) +{ + int return_code = LLSEC_DIGEST_SUCCESS; + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + + mbedtls_md_context_t* md_ctx = mbedtls_calloc(1, sizeof(mbedtls_md_context_t)); + if (md_ctx == NULL) { + return_code = LLSEC_DIGEST_ERROR; + } + + if (return_code == LLSEC_DIGEST_SUCCESS){ + mbedtls_md_init(md_ctx); + + return_code = mbedtls_md_setup(md_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), 0); + if (return_code != LLSEC_DIGEST_SUCCESS) { + mbedtls_md_free(md_ctx); + } + } + + if (return_code == LLSEC_DIGEST_SUCCESS){ + return_code = mbedtls_md_starts(md_ctx); + if (return_code != LLSEC_DIGEST_SUCCESS) { + mbedtls_md_free(md_ctx); + } else { + *native_id = md_ctx; + } + } + return return_code; +} + +/** + * @brief Gets for the given algorithm the message digest description. + * + * @param[in] algorithm_name Null terminated string that describes the algorithm. + * @param[out] algorithm_desc Description of the digest. + * + * @return The algorithm ID on success or -1 on error. + * + * @warning algorithm_name must not be used outside of the VM task or saved. + */ +int32_t LLSEC_DIGEST_IMPL_get_algorithm_description(uint8_t* algorithm_name, LLSEC_DIGEST_algorithm_desc* algorithm_desc) +{ + int32_t return_code = LLSEC_DIGEST_SUCCESS; + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + int32_t nb_algorithms = sizeof(available_digest_algorithms) / sizeof(LLSEC_DIGEST_algorithm); + LLSEC_DIGEST_algorithm* algorithm = &available_digest_algorithms[0]; + + while (--nb_algorithms >= 0) { + if (strcmp((char*)algorithm_name, (algorithm->name)) == 0) { + (void) memcpy(algorithm_desc, &(algorithm->description), sizeof(LLSEC_DIGEST_algorithm_desc)); + break; + } + algorithm++; + } + + if (nb_algorithms >= 0) + { + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + return_code = (int32_t)algorithm; + } else { + return_code = LLSEC_DIGEST_ERROR; + } + return return_code; +} + +/** + * @brief Initializes a Digest resource. + * + * @param[in] algorithm_id The algorithm ID. + * + * @return The nativeId of the newly initialized resource. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_DIGEST_IMPL_init(int32_t algorithm_id) +{ + int32_t return_code = 0; + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + void* native_id = NULL; + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_DIGEST_algorithm* algorithm = (LLSEC_DIGEST_algorithm*)algorithm_id; + + return_code = algorithm->init((void**)&native_id); + + if (return_code != LLSEC_DIGEST_SUCCESS) { + SNI_throwNativeException(return_code, "LLSEC_DIGEST_IMPL_init failed"); + } else { + /* register SNI native resource */ + if (SNI_registerResource(native_id, algorithm->close, NULL) != SNI_OK) { + SNI_throwNativeException(LLSEC_DIGEST_ERROR, "Can't register SNI native resource"); + algorithm->close((void*)native_id); + return_code = LLSEC_DIGEST_ERROR; + } else { + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (int32_t)native_id; + } + } + return return_code; +} + +/** + * @brief Closes the resource related to the native ID. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] native_id The resource's native ID. + * + * @note Throws NativeException on error. + */ +void LLSEC_DIGEST_IMPL_close(int32_t algorithm_id, int32_t native_id) +{ + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_DIGEST_algorithm* algorithm = (LLSEC_DIGEST_algorithm*)algorithm_id; + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + algorithm->close((void*)native_id); + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + if (SNI_unregisterResource((void*)native_id, (SNI_closeFunction)algorithm->close) != SNI_OK) { + SNI_throwNativeException(LLSEC_DIGEST_ERROR, "Can't unregister SNI native resource"); + } +} + +/** + * @brief Updates the input data. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] native_id The resource's native ID. + * @param[in] buffer The buffer containing the input data to add. + * @param[in] buffer_offset The buffer offset. + * @param[in] buffer_length The buffer length. + * + * @note Throws NativeException on error. + * + * @warning buffer must not be used outside of the VM task or saved. + */ +void LLSEC_DIGEST_IMPL_update(int32_t algorithm_id, int32_t native_id, uint8_t* buffer, int32_t buffer_offset, int32_t buffer_length) +{ + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_DIGEST_algorithm* algorithm = (LLSEC_DIGEST_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + int returnCode = algorithm->update((void*)native_id, &buffer[buffer_offset], buffer_length); + + if (returnCode != LLSEC_DIGEST_SUCCESS) { + SNI_throwNativeException(returnCode, "LLSEC_DIGEST_IMPL_update failed"); + } +} + +/** + * @brief Calculates the hash. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] native_id The resource's native ID. + * @param[out] out The output buffer containing the digest value. + * @param[in] out_offset The output offset. + * @param[in] out_length The output length. + * + * @note Throws NativeException on error. + * + * @warning out must not be used outside of the VM task or saved. + */ +void LLSEC_DIGEST_IMPL_digest(int32_t algorithm_id, int32_t native_id, uint8_t* out, int32_t out_offset, int32_t out_length) +{ + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_DIGEST_algorithm* algorithm = (LLSEC_DIGEST_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + int returnCode = algorithm->digest((void*)native_id, &out[out_offset], &out_length); + + if (returnCode != LLSEC_DIGEST_SUCCESS) { + SNI_throwNativeException(returnCode, "LLSEC_DIGEST_IMPL_digest failed"); + } +} + +/** + * @brief Gets the id of the native close function. + * @param[in] algorithm_id The algorithm ID. + * + * @return the id of the static native close function. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_DIGEST_IMPL_get_close_id(int32_t algorithm_id) +{ + LLSEC_DIGEST_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_DIGEST_algorithm* algorithm = (LLSEC_DIGEST_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + return (int32_t)algorithm->close; +} diff --git a/bsp/projects/microej/security/src/LLSEC_KEY_FACTORY_impl.c b/bsp/projects/microej/security/src/LLSEC_KEY_FACTORY_impl.c new file mode 100644 index 0000000..004b9b5 --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_KEY_FACTORY_impl.c @@ -0,0 +1,427 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mbedtls/platform.h" + +#define LLSEC_KEY_FACTORY_SUCCESS 0 +#define LLSEC_KEY_FACTORY_ERROR -1 + +//#define LLSEC_KEY_FACTORY_DEBUG + +#ifdef LLSEC_KEY_FACTORY_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_KEY_FACTORY_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_KEY_FACTORY_DEBUG_TRACE(...) ((void)0) +#endif + +// cppcheck-suppress misra-c2012-8.9 // Define here for code readability even if it called once in this file. +static const char* pkcs8_format = "PKCS#8"; +// cppcheck-suppress misra-c2012-8.9 // Define here for code readability even if it called once in this file. +static const char* x509_format = "X.509"; + +typedef int32_t (*LLSEC_KEY_FACTORY_get_private_key_data)(LLSEC_priv_key* priv_key, uint8_t* encoded_key, int32_t encoded_key_length); +typedef int32_t (*LLSEC_KEY_FACTORY_get_public_key_data)(LLSEC_pub_key* pub_key, uint8_t* encoded_key, int32_t encoded_key_length); +typedef void (*LLSEC_KEY_FACTORY_key_close)(void* native_id); + +typedef struct { + char* name; + LLSEC_KEY_FACTORY_get_private_key_data get_private_key_data; + LLSEC_KEY_FACTORY_get_public_key_data get_public_key_data; + LLSEC_KEY_FACTORY_key_close private_key_close; + LLSEC_KEY_FACTORY_key_close public_key_close; +} LLSEC_KEY_FACTORY_algorithm; + +static int32_t LLSEC_KEY_FACTORY_RSA_mbedtls_get_private_key_data(LLSEC_priv_key* priv_key, uint8_t* encoded_key, int32_t encoded_key_length); +static int32_t LLSEC_KEY_FACTORY_RSA_mbedtls_get_public_key_data(LLSEC_pub_key* pub_key, uint8_t* encoded_key, int32_t encoded_key_length); +static int32_t LLSEC_KEY_FACTORY_EC_mbedtls_get_private_key_data(LLSEC_priv_key* priv_key, uint8_t* encoded_key, int32_t encoded_key_length); +static int32_t LLSEC_KEY_FACTORY_EC_mbedtls_get_public_key_data(LLSEC_pub_key* pub_key, uint8_t* encoded_key, int32_t encoded_key_length); +static void LLSEC_KEY_FACTORY_mbedtls_private_key_close(void* native_id); +static void LLSEC_KEY_FACTORY_mbedtls_public_key_close(void* native_id); + +// cppcheck-suppress misra-c2012-8.9 // Define here for code readability even if it called once in this file. +static LLSEC_KEY_FACTORY_algorithm available_key_algorithms[2] = { + { + .name = "RSA", + .get_private_key_data = LLSEC_KEY_FACTORY_RSA_mbedtls_get_private_key_data, + .get_public_key_data = LLSEC_KEY_FACTORY_RSA_mbedtls_get_public_key_data, + .private_key_close = LLSEC_KEY_FACTORY_mbedtls_private_key_close, + .public_key_close = LLSEC_KEY_FACTORY_mbedtls_public_key_close + }, + { + .name = "EC", + .get_private_key_data = LLSEC_KEY_FACTORY_EC_mbedtls_get_private_key_data, + .get_public_key_data = LLSEC_KEY_FACTORY_EC_mbedtls_get_public_key_data, + .private_key_close = LLSEC_KEY_FACTORY_mbedtls_private_key_close, + .public_key_close = LLSEC_KEY_FACTORY_mbedtls_public_key_close + } +}; + +static int32_t LLSEC_KEY_FACTORY_RSA_mbedtls_get_private_key_data(LLSEC_priv_key* priv_key, uint8_t* encoded_key, int32_t encoded_key_length) +{ + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + + int return_code = LLSEC_KEY_FACTORY_SUCCESS; + priv_key->type = TYPE_RSA; + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + return_code = mbedtls_pk_parse_key(&pk, encoded_key, encoded_key_length, NULL, 0); + + if(return_code != LLSEC_KEY_FACTORY_SUCCESS) { + LLSEC_KEY_FACTORY_DEBUG_TRACE("mbedtls private key parsing failed"); + mbedtls_free(priv_key); + } + + if(return_code == LLSEC_KEY_FACTORY_SUCCESS) { + priv_key->key = (char*)mbedtls_pk_rsa(pk); + + if (priv_key->key == NULL) { + SNI_throwNativeException(-1, "RSA context extraction failed"); + mbedtls_free(priv_key); + return_code = LLSEC_KEY_FACTORY_ERROR; + } + } + + if(return_code == LLSEC_KEY_FACTORY_SUCCESS) { + + void* native_id = (void*)priv_key; + if (SNI_registerResource(native_id, (SNI_closeFunction)LLSEC_KEY_FACTORY_mbedtls_private_key_close, NULL) != SNI_OK) { + SNI_throwNativeException(LLSEC_KEY_FACTORY_ERROR, "Can't register SNI native resource"); + mbedtls_rsa_free((mbedtls_rsa_context*)priv_key->key); + mbedtls_free(priv_key); + return_code = LLSEC_KEY_FACTORY_ERROR; + } else { + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (int32_t)native_id; + } + } + + return return_code; +} + +static int32_t LLSEC_KEY_FACTORY_RSA_mbedtls_get_public_key_data(LLSEC_pub_key* pub_key, uint8_t* encoded_key, int32_t encoded_key_length) +{ + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + + int return_code = LLSEC_KEY_FACTORY_SUCCESS; + pub_key->type = TYPE_RSA; + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + return_code = mbedtls_pk_parse_public_key(&pk, encoded_key, encoded_key_length); + + if(return_code != LLSEC_KEY_FACTORY_SUCCESS) { + LLSEC_KEY_FACTORY_DEBUG_TRACE("mbedtls public key parsing failed"); + mbedtls_free(pub_key); + } + + if(return_code == LLSEC_KEY_FACTORY_SUCCESS) { + pub_key->key = (char*)mbedtls_pk_rsa(pk); + + if (pub_key->key == NULL) { + SNI_throwNativeException(LLSEC_KEY_FACTORY_ERROR, "RSA public key extraction failed"); + mbedtls_free(pub_key); + return_code = LLSEC_KEY_FACTORY_ERROR; + } + } + + if(return_code == LLSEC_KEY_FACTORY_SUCCESS) { + + void* native_id = (void*)pub_key; + if (SNI_registerResource(native_id, (SNI_closeFunction)LLSEC_KEY_FACTORY_mbedtls_public_key_close, NULL) != SNI_OK) { + SNI_throwNativeException(LLSEC_KEY_FACTORY_ERROR, "Can't register SNI native resource"); + mbedtls_rsa_free((mbedtls_rsa_context*)pub_key->key); + mbedtls_free(pub_key); + return_code = LLSEC_KEY_FACTORY_ERROR; + } else { + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (int32_t)native_id; + } + } + + return return_code; +} + +static int32_t LLSEC_KEY_FACTORY_EC_mbedtls_get_private_key_data(LLSEC_priv_key* priv_key, uint8_t* encoded_key, int32_t encoded_key_length) +{ + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + LLSEC_KEY_FACTORY_DEBUG_TRACE("encLen %d, strlen: %zu, enc:%s \n", encoded_key_length, strlen((char*)encoded_key), encoded_key); + + int return_code = LLSEC_KEY_FACTORY_SUCCESS; + priv_key->type = TYPE_ECDSA; + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + return_code = mbedtls_pk_parse_key(&pk, encoded_key, encoded_key_length, NULL, 0); + + if (return_code != LLSEC_KEY_FACTORY_SUCCESS) { + LLSEC_KEY_FACTORY_DEBUG_TRACE("parse private key error: %d\n", return_code); + mbedtls_free(priv_key); + } + + if (return_code == LLSEC_KEY_FACTORY_SUCCESS) { + + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s 11.\n", __func__); + priv_key->key = (char*)mbedtls_pk_ec(pk); + + if (priv_key->key == NULL) { + SNI_throwNativeException(-1, "EC private key extraction failed"); + mbedtls_free(priv_key); + return_code = LLSEC_KEY_FACTORY_ERROR; + } + } + + + if (return_code == LLSEC_KEY_FACTORY_SUCCESS) { + + void* native_id = (void*)priv_key; + if (SNI_registerResource(native_id, (SNI_closeFunction)LLSEC_KEY_FACTORY_mbedtls_private_key_close, NULL) != SNI_OK) { + SNI_throwNativeException(-1, "Can't register SNI native resource"); + mbedtls_ecdsa_free((mbedtls_ecdsa_context*)priv_key->key); + mbedtls_free(priv_key); + return_code = LLSEC_KEY_FACTORY_ERROR; + } else { + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (int32_t)native_id; + } + } + + return return_code; +} + +static int32_t LLSEC_KEY_FACTORY_EC_mbedtls_get_public_key_data(LLSEC_pub_key* pub_key, uint8_t* encoded_key, int32_t encoded_key_length) +{ + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + + int return_code = LLSEC_KEY_FACTORY_SUCCESS; + + pub_key->type = TYPE_ECDSA; + + mbedtls_pk_context pk; + mbedtls_pk_init(&pk); + return_code = mbedtls_pk_parse_public_key(&pk, encoded_key, encoded_key_length); + + if(return_code != LLSEC_KEY_FACTORY_SUCCESS) { + LLSEC_KEY_FACTORY_DEBUG_TRACE("parse public key error: %d\n", return_code); + mbedtls_free(pub_key); + } + + if(return_code == LLSEC_KEY_FACTORY_SUCCESS) { + pub_key->key = (char*)mbedtls_pk_ec(pk); + + if (pub_key->key == NULL) { + SNI_throwNativeException(-1, "EC context extraction failed"); + mbedtls_free(pub_key); + return_code = LLSEC_KEY_FACTORY_ERROR; + } + } + + if(return_code == LLSEC_KEY_FACTORY_SUCCESS) { + void* native_id = (void*)pub_key; + if (SNI_registerResource(native_id, (SNI_closeFunction)LLSEC_KEY_FACTORY_mbedtls_public_key_close, NULL) != SNI_OK) { + SNI_throwNativeException(-1, "Can't register SNI native resource"); + mbedtls_ecdsa_free((mbedtls_ecdsa_context*)pub_key->key); + mbedtls_free(pub_key); + return_code = LLSEC_KEY_FACTORY_ERROR; + } else { + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (int32_t)native_id; + } + } + + return return_code; + +} + +static void LLSEC_KEY_FACTORY_mbedtls_private_key_close(void* native_id) +{ + // cppcheck-suppress misra-c2012-11.5 // Abstract data type for SNI usage + LLSEC_priv_key* key = (LLSEC_priv_key*)native_id; + + if (key->type == TYPE_RSA) { + mbedtls_rsa_free((mbedtls_rsa_context*)key->key); + } else { + mbedtls_ecdsa_free((mbedtls_ecdsa_context*)key->key); + } + mbedtls_free(key); +} + +static void LLSEC_KEY_FACTORY_mbedtls_public_key_close(void* native_id) +{ + // cppcheck-suppress misra-c2012-11.5 // Abstract data type for SNI usage + LLSEC_pub_key* key = (LLSEC_pub_key*)native_id; + if (key->type == TYPE_RSA) { + mbedtls_rsa_free((mbedtls_rsa_context*)key->key); + } else { + mbedtls_ecdsa_free((mbedtls_ecdsa_context*)key->key); + } + mbedtls_free(key); +} +/*------------------------------------------Above is internal implementation--------------------------------------------------------*/ + +/** + * @brief Gets for the given algorithm the key factory description. + * + * @param[in] algorithm_name Null terminated string that describes the algorithm. + * + * @return The algorithm ID on success or -1 on error. + */ +int32_t LLSEC_KEY_FACTORY_IMPL_get_algorithm_description(uint8_t* algorithm_name) +{ + int32_t return_code = LLSEC_KEY_FACTORY_SUCCESS; + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + int32_t nb_algorithms = sizeof(available_key_algorithms) / sizeof(LLSEC_KEY_FACTORY_algorithm); + LLSEC_KEY_FACTORY_algorithm* algorithm = &available_key_algorithms[0]; + + while (--nb_algorithms >= 0) { + if (strcmp((char*)algorithm_name, algorithm->name) == 0) { + break; + } + algorithm++; + } + + if (nb_algorithms >= 0) + { + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + return_code = (int32_t)algorithm; + } else { + return_code = LLSEC_KEY_FACTORY_ERROR; + } + return return_code; +} + +/** + * @brief Gets the native public key corresponding to the encoded data. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] format_name Null terminated string that describes the key format. + * @param[in] encoded_key The public key in its encoded form. + * @param[in] encoded_key_length The encoded key length. + * + * @return pointer on the C structure holding the key information. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_KEY_FACTORY_IMPL_get_public_key_data(int32_t algorithm_id, uint8_t* format_name, uint8_t* encoded_key, int32_t encoded_key_length) +{ + int32_t return_code = LLSEC_KEY_FACTORY_SUCCESS; + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + LLSEC_pub_key* public_key = NULL; + + + if (strcmp((char*)format_name, x509_format) != 0) { + SNI_throwNativeException(LLSEC_KEY_FACTORY_ERROR, "Invalid format name"); + return_code = LLSEC_KEY_FACTORY_ERROR; + } + + if (return_code == LLSEC_KEY_FACTORY_SUCCESS) { + public_key = (LLSEC_pub_key*)mbedtls_calloc(1, sizeof(LLSEC_pub_key)); + if (public_key == NULL) { + SNI_throwNativeException(LLSEC_KEY_FACTORY_ERROR, "Can't allocate LLSEC_pub_key structure"); + return_code = LLSEC_KEY_FACTORY_ERROR; + } + } + + if (return_code == LLSEC_KEY_FACTORY_SUCCESS) { + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_KEY_FACTORY_algorithm* algorithm = (LLSEC_KEY_FACTORY_algorithm*)algorithm_id; + return_code = algorithm->get_public_key_data(public_key, encoded_key, encoded_key_length); + } + + return return_code; +} + +/** + * @brief Gets the native private key corresponding to the encoded data. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] format_name Null terminated string that describes the key format. + * @param[out] key_data The private key in the native format. + * @param[out] key_data_length The private key length. + * @param[in] encoded_key The private key in its encoded form. + * @param[in] encoded_key_length The encoded key length. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_KEY_FACTORY_IMPL_get_private_key_data(int32_t algorithm_id, uint8_t* format_name, uint8_t* encoded_key, int32_t encoded_key_length) +{ + int32_t return_code = LLSEC_KEY_FACTORY_SUCCESS; + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + LLSEC_priv_key* private_key = NULL; + + if (strcmp((char*)format_name, pkcs8_format) != 0) { + SNI_throwNativeException(-1, "Invalid format name"); + return_code = LLSEC_KEY_FACTORY_ERROR; + } + + if (return_code == LLSEC_KEY_FACTORY_SUCCESS) { + private_key = (LLSEC_priv_key*)mbedtls_calloc(1, sizeof(LLSEC_priv_key)); + if (private_key == NULL) { + SNI_throwNativeException(-1, "Can't allocate LLSEC_priv_key structure"); + return_code = LLSEC_KEY_FACTORY_ERROR; + } + } + + if (return_code == LLSEC_KEY_FACTORY_SUCCESS) { + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_KEY_FACTORY_algorithm* algorithm = (LLSEC_KEY_FACTORY_algorithm*)algorithm_id; + return_code = algorithm->get_private_key_data(private_key, encoded_key, encoded_key_length); + } + + return return_code; +} + +/** + * @brief Get the pointer for the close private key method to be used as a close resource callback with SNI. + * + * @param[in] algorithm_id algorithm pointer + * + * @return the pointer for the close method. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_KEY_FACTORY_IMPL_get_private_key_close_id(int32_t algorithm_id) +{ + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_KEY_FACTORY_algorithm* algorithm = (LLSEC_KEY_FACTORY_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + return (int32_t)algorithm->private_key_close; +} + +/** + * @brief Get the pointer for the close public key method to be used as a close resource callback with SNI. + * + * @param[in] algorithm_id algorithm pointer + * + * @return the pointer for the close method. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_KEY_FACTORY_IMPL_get_public_key_close_id(int32_t algorithm_id) +{ + LLSEC_KEY_FACTORY_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_KEY_FACTORY_algorithm* algorithm = (LLSEC_KEY_FACTORY_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + return (int32_t)algorithm->public_key_close; +} diff --git a/bsp/projects/microej/security/src/LLSEC_KEY_PAIR_GENERATOR_impl.c b/bsp/projects/microej/security/src/LLSEC_KEY_PAIR_GENERATOR_impl.c new file mode 100644 index 0000000..0b5052e --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_KEY_PAIR_GENERATOR_impl.c @@ -0,0 +1,312 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include + +#include +#include +#include +#include + +#include "mbedtls/platform.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/dhm.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/ecdsa.h" +#include "mbedtls/entropy.h" +#include "mbedtls/rsa.h" + +#define LLSEC_KEY_PAIR_GENERATOR_SUCCESS 0 +#define LLSEC_KEY_PAIR_GENERATOR_ERROR -1 + +//#define LLSEC_KEY_PAIR_GENERATOR_DEBUG + +#ifdef LLSEC_KEY_PAIR_GENERATOR_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE(...) ((void)0) +#endif + +typedef void (*LLSEC_KEY_PAIR_GENERATOR_close)(void* native_id); + +//RSA +static int32_t LLSEC_KEY_PAIR_GENERATOR_RSA_mbedtls_generateKeyPair(int32_t rsa_Key_size, int32_t rsa_public_exponent); + +//EC +static int32_t LLSEC_KEY_PAIR_GENERATOR_EC_mbedtls_generateKeyPair(uint8_t* ec_curve_stdname); + +//common +static void LLSEC_KEY_PAIR_GENERATOR_mbedtls_close(void* native_id); + +typedef struct { + char* name; + LLSEC_KEY_PAIR_GENERATOR_close close; +} LLSEC_KEY_PAIR_GENERATOR_algorithm; + +// cppcheck-suppress misra-c2012-8.9 // Define here for code readability even if it called once in this file. +static LLSEC_KEY_PAIR_GENERATOR_algorithm supportedAlgorithms[2] = { + { + .name = "RSA", + .close = LLSEC_KEY_PAIR_GENERATOR_mbedtls_close + }, + { + .name = "EC", + .close = LLSEC_KEY_PAIR_GENERATOR_mbedtls_close + } + +}; + +static int32_t LLSEC_KEY_PAIR_GENERATOR_RSA_mbedtls_generateKeyPair(int32_t rsa_Key_size, int32_t rsa_public_exponent) +{ + int return_code; + mbedtls_rsa_context* ctx = mbedtls_calloc(1, sizeof(mbedtls_rsa_context)); //RSA key structure + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char* pers = llsec_gen_random_str_internal(8); + LLSEC_priv_key* key = NULL; + void* native_id = NULL; + + mbedtls_entropy_init(&entropy); //init entropy structure + mbedtls_ctr_drbg_init(&ctr_drbg); //Initial random structure + + /* init rsa structure */ + mbedtls_rsa_init(ctx, MBEDTLS_RSA_PKCS_V21, //padding OAEP + MBEDTLS_MD_SHA256); //SHA256 + + /* update seed according personal string */ + return_code = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const uint8_t*)pers, strlen(pers)); + if (return_code != LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE("%s \n", __func__); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + mbedtls_rsa_free(ctx); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + + if (return_code == LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + /*Generate ras key pair*/ + (void)mbedtls_rsa_gen_key(ctx, mbedtls_ctr_drbg_random, //API of generating random + &ctr_drbg, //random structure + rsa_Key_size, //the size of public key + rsa_public_exponent); //publick key exponent 0x01001 + + key = (LLSEC_priv_key*)mbedtls_calloc(1, sizeof(LLSEC_priv_key)); + if (key == NULL) { + LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE("%s \n", __func__); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + mbedtls_rsa_free(ctx); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + } + + if (return_code == LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + key->key = (char*)ctx; + key->type = TYPE_RSA; + + // Register the key to be managed by SNI as a native resource. + // the close callback when be called when the key is collected by the GC + // The key is freed in the close callback + native_id = (void*)key; + if (SNI_registerResource(native_id, LLSEC_KEY_PAIR_GENERATOR_mbedtls_close, NULL) != SNI_OK) { + SNI_throwNativeException(-1, "Can't register SNI native resource"); + + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + mbedtls_rsa_free(ctx); + mbedtls_free(key); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + } + + if (return_code == LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (uint32_t)native_id; + } + + return return_code; +} + +static int32_t LLSEC_KEY_PAIR_GENERATOR_EC_mbedtls_generateKeyPair(uint8_t* ec_curve_stdname) +{ + (void) ec_curve_stdname; // Unused input parameter + + int return_code; + mbedtls_ecdsa_context* ctx = mbedtls_calloc(1, sizeof(mbedtls_ecdsa_context)); + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char* pers = llsec_gen_random_str_internal(8); + LLSEC_priv_key* key = NULL; + void* native_id = NULL; + + mbedtls_ecdsa_init(ctx); + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + return_code = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const uint8_t*)pers, strlen(pers)); + if (return_code != LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE("%s \n", __func__); + mbedtls_ecdsa_free(ctx); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + + if (return_code == LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + /* Generate ecdsa Key pair */ + return_code = mbedtls_ecdsa_genkey(ctx, + MBEDTLS_ECP_DP_SECP256R1, + mbedtls_ctr_drbg_random, &ctr_drbg); + if (return_code != LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE("%s \n", __func__); + mbedtls_ecdsa_free(ctx); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + } + + if (return_code == LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + key = (LLSEC_priv_key*)mbedtls_calloc(1, sizeof(LLSEC_priv_key)); + if (key == NULL) { + LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE("%s \n", __func__); + mbedtls_ecdsa_free(ctx); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + } + + if (return_code == LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + key->key = (char*)ctx; + key->type = TYPE_ECDSA; + + // Register the key to be managed by SNI as a native resource. + // the close callback when be called when the key is collected by the GC + // The key is freed in the close callback + native_id = (void*)key; + if (SNI_registerResource(native_id, LLSEC_KEY_PAIR_GENERATOR_mbedtls_close, NULL) != SNI_OK) { + SNI_throwNativeException(LLSEC_KEY_PAIR_GENERATOR_ERROR, "Can't register SNI native resource"); + + mbedtls_ecdsa_free(ctx); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + mbedtls_free(key); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + } + + if (return_code == LLSEC_KEY_PAIR_GENERATOR_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (uint32_t)native_id; + } + return return_code; +} + +static void LLSEC_KEY_PAIR_GENERATOR_mbedtls_close(void* native_id) +{ + LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.5 // Abstract data type for SNI usage + LLSEC_priv_key* key = (LLSEC_priv_key*)native_id; + + if (key->type == TYPE_RSA) { + mbedtls_rsa_free((mbedtls_rsa_context*)key->key); + } else { + mbedtls_ecdsa_free((mbedtls_ecdsa_context*)key->key); + } + mbedtls_free(key); +} + + +int32_t LLSEC_KEY_PAIR_GENERATOR_IMPL_get_algorithm(uint8_t* algorithm_name) +{ + int32_t return_code; + LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE("%s \n", __func__); + + int32_t nb_algorithms = sizeof(supportedAlgorithms) / sizeof(LLSEC_KEY_PAIR_GENERATOR_algorithm); + LLSEC_KEY_PAIR_GENERATOR_algorithm* algorithm = &supportedAlgorithms[0]; + + while (--nb_algorithms >= 0) { + if (strcmp((char*)algorithm_name, algorithm->name) == 0) { + break; + } + algorithm++; + } + + if (nb_algorithms >= 0) + { + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + return_code = (int32_t)algorithm; + } else { + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + return return_code; +} + +int32_t LLSEC_KEY_PAIR_GENERATOR_IMPL_generateKeyPair(int32_t algorithm_id, int32_t rsa_key_size, int32_t rsa_public_exponent, uint8_t* ec_curve_stdname) +{ + int32_t return_code; + LLSEC_KEY_PAIR_GENERATOR_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_KEY_PAIR_GENERATOR_algorithm* algorithm = (LLSEC_KEY_PAIR_GENERATOR_algorithm*)algorithm_id; + if ((strcmp(algorithm->name, "RSA") == 0)) { + return_code = LLSEC_KEY_PAIR_GENERATOR_RSA_mbedtls_generateKeyPair(rsa_key_size, rsa_public_exponent); + } else if ((strcmp(algorithm->name, "EC") == 0)) { + return_code = LLSEC_KEY_PAIR_GENERATOR_EC_mbedtls_generateKeyPair(ec_curve_stdname); + } else{ + // Algorithm not found error. + // this should never happen because the algorithm_id is a valid algorithm at this level. + SNI_throwNativeException(LLSEC_KEY_PAIR_GENERATOR_ERROR, "Unsupported algorithm"); + return_code = LLSEC_KEY_PAIR_GENERATOR_ERROR; + } + return return_code; +} + +int32_t LLSEC_KEY_PAIR_GENERATOR_IMPL_get_close_id(int32_t algorithm_id) +{ + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_KEY_PAIR_GENERATOR_algorithm* algorithm = (LLSEC_KEY_PAIR_GENERATOR_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + return (int32_t)algorithm->close; +} diff --git a/bsp/projects/microej/security/src/LLSEC_MAC_impl.c b/bsp/projects/microej/security/src/LLSEC_MAC_impl.c new file mode 100644 index 0000000..6294dbb --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_MAC_impl.c @@ -0,0 +1,334 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mbedtls/platform.h" +#include "mbedtls/md.h" + +#define LLSEC_MAC_SUCCESS 0 +#define LLSEC_MAC_ERROR -1 + +//#define LLSEC_MAC_DEBUG + +#ifdef LLSEC_MAC_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_MAC_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_MAC_DEBUG_TRACE(...) ((void)0) +#endif + +typedef int (*LLSEC_MAC_init)(void** native_id, uint8_t* key, int32_t key_length); +typedef int (*LLSEC_MAC_update)(void* native_id, uint8_t* buffer, int32_t buffer_length); +typedef int (*LLSEC_MAC_do_final)(void* native_id, uint8_t* out, int32_t out_length); +typedef int (*LLSEC_MAC_reset)(void* native_id); +typedef void (*LLSEC_MAC_close)(void* native_id); + +typedef struct { + char* name; + LLSEC_MAC_init init; + LLSEC_MAC_update update; + LLSEC_MAC_do_final do_final; + LLSEC_MAC_reset reset; + LLSEC_MAC_close close; + LLSEC_MAC_algorithm_desc description; +} LLSEC_MAC_algorithm; + +static int mbedtls_mac_HmacSha256_init(void** native_id, uint8_t* key, int32_t key_length); +static int mbedtls_mac_update(void* native_id, uint8_t* buffer, int32_t buffer_length); +static int mbedtls_mac_do_final(void* native_id, uint8_t* out, int32_t out_length); +static int mbedtls_mac_reset(void* native_id); +static void mbedtls_mac_close(void* native_id); + +// cppcheck-suppress misra-c2012-8.9 // Define here for code readability even if it called once in this file. +static LLSEC_MAC_algorithm available_mac_algorithms[1] = { + + { + .name = "HmacSHA256", + .init = mbedtls_mac_HmacSha256_init, + .update = mbedtls_mac_update, + .do_final = mbedtls_mac_do_final, + .reset = mbedtls_mac_reset, + .close = mbedtls_mac_close, + { + .mac_length = 32 + } + } +}; + +static int mbedtls_mac_HmacSha256_init(void** native_id, uint8_t* key, int32_t key_length) +{ + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + int return_code = LLSEC_MAC_SUCCESS; + mbedtls_md_context_t* md_ctx = LLSEC_calloc(1, sizeof(mbedtls_md_context_t)); + if (md_ctx == NULL) { + return_code = LLSEC_MAC_ERROR; + } + + if (return_code == LLSEC_MAC_SUCCESS) { + mbedtls_md_init(md_ctx); + return_code = mbedtls_md_setup(md_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1); + if (return_code != LLSEC_MAC_SUCCESS) { + LLSEC_free(md_ctx); + return_code = LLSEC_MAC_ERROR; + } + } + + if (return_code == LLSEC_MAC_SUCCESS) { + return_code = mbedtls_md_hmac_starts(md_ctx, key, key_length); + if (return_code != LLSEC_MAC_SUCCESS) { + LLSEC_free(md_ctx); + return_code = LLSEC_MAC_ERROR; + } else { + *native_id = md_ctx; + } + } + + return return_code; +} + +static int mbedtls_mac_update(void* native_id, uint8_t* buffer, int32_t buffer_length) +{ + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + mbedtls_md_context_t* md_ctx = (mbedtls_md_context_t*)native_id; + return mbedtls_md_hmac_update(md_ctx, buffer, buffer_length); +} + +static int mbedtls_mac_do_final(void* native_id, uint8_t* out, int32_t out_length) +{ + (void) native_id; // Unused input parameter + (void) out_length; // Unused input parameter + + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + mbedtls_md_context_t* md_ctx = (mbedtls_md_context_t*)native_id; + return mbedtls_md_hmac_finish(md_ctx, out); +} + +static int mbedtls_mac_reset(void* native_id) +{ + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + mbedtls_md_context_t* md_ctx = (mbedtls_md_context_t*)native_id; + return mbedtls_md_hmac_reset(md_ctx); +} + +static void mbedtls_mac_close(void* native_id) +{ + LLSEC_MAC_DEBUG_TRACE("%s native_id:%p\n", __func__, native_id); + LLSEC_free(native_id); +} + +/** + * @brief Gets for the given algorithm the message digest description. + * + * @param[in] algorithm_name Null terminated string that describes the algorithm. + * @param[out] algorithm_desc Description of the MAC algorithm. + * + * @return The algorithm ID on success or -1 on error. + * + * @warning algorithm_name must not be used outside of the VM task or saved. + */ +int32_t LLSEC_MAC_IMPL_get_algorithm_description(uint8_t* algorithm_name, LLSEC_MAC_algorithm_desc* algorithm_desc) +{ + int32_t return_code; + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + + int32_t nb_algorithms = sizeof(available_mac_algorithms) / sizeof(LLSEC_MAC_algorithm); + LLSEC_MAC_algorithm* algorithm = &available_mac_algorithms[0]; + + while (--nb_algorithms >= 0) { + if (strcmp((const char*)algorithm_name, algorithm->name) == 0) { + (void) memcpy(algorithm_desc, &(algorithm->description), sizeof(LLSEC_MAC_algorithm_desc)); + break; + } + algorithm++; + } + + if (nb_algorithms >= 0) + { + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + return_code = (int32_t)algorithm; + } else { + return_code = LLSEC_MAC_ERROR; + } + return return_code; +} + +/** + * @brief Initializes a Mac resource. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] key The MAC key. + * @param[in] key_length The key length. + * + * @return The native ID of the resource. + * + * @note Throws NativeException on error. + * + * @warning key must not be used outside of the VM task or saved. + */ +int32_t LLSEC_MAC_IMPL_init(int32_t algorithm_id, uint8_t* key, int32_t key_length) +{ + int32_t return_code; + + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + + void* native_id = NULL; + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_MAC_algorithm* algorithm = (LLSEC_MAC_algorithm*)algorithm_id; + + return_code = algorithm->init(&native_id, key, key_length); + + if (return_code != LLSEC_MAC_SUCCESS) { + SNI_throwNativeException(return_code, "LLSEC_MAC_IMPL_init failed\n"); + } + + // register SNI native resource + if (SNI_registerResource(native_id, algorithm->close, NULL) != SNI_OK) { + SNI_throwNativeException(-1, "Can't register SNI native resource"); + algorithm->close(native_id); + return_code = LLSEC_MAC_ERROR; + } else { + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (int32_t)native_id; + } + return return_code; +} + +/** + * @brief Processes the provided data to update the MAC resource. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] native_id The native ID. + * @param[in] buffer The buffer containing the data to be processed. + * @param[in] buffer_offset The buffer offset. + * @param[in] buffer_length The buffer length. + * + * @note Throws NativeException on error. + * + * @warning buffer must not be used outside of the VM task or saved. + */ +void LLSEC_MAC_IMPL_update(int32_t algorithm_id, int32_t native_id, uint8_t* buffer, int32_t buffer_offset, int32_t buffer_length) +{ + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_MAC_algorithm* algorithm = (LLSEC_MAC_algorithm*)algorithm_id; + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + int returnCode = algorithm->update((void*)native_id, &buffer[buffer_offset], buffer_length); + + if (returnCode != LLSEC_MAC_SUCCESS) { + SNI_throwNativeException(returnCode, "LLSEC_MAC_IMPL_update failed"); + } +} + +/** + * @brief Finishes the MAC operation. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] native_id The native ID. + * @param[out] out The MAC result. + * @param[in] out_offset The offset of the out buffer. + * @param[in] out_length The length of the out buffer. + * + * @note Throws NativeException on error. + * + * @warning out must not be used outside of the VM task or saved. + */ +void LLSEC_MAC_IMPL_do_final(int32_t algorithm_id, int32_t native_id, uint8_t* out, int32_t out_offset, int32_t out_length) +{ + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_MAC_algorithm* algorithm = (LLSEC_MAC_algorithm*)algorithm_id; + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + int returnCode = algorithm->do_final((void*)native_id, &out[out_offset], out_length); + + if (returnCode != LLSEC_MAC_SUCCESS) { + SNI_throwNativeException(returnCode, "LLSEC_MAC_IMPL_do_final failed"); + } +} + +/** + * @brief Resets the MAC resource. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] native_id The native ID. + * + * @note Throws NativeException on error. + */ +void LLSEC_MAC_IMPL_reset(int32_t algorithm_id, int32_t native_id) +{ + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_MAC_algorithm* algorithm = (LLSEC_MAC_algorithm*)algorithm_id; + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + int returnCode = algorithm->reset((void*)native_id); + + if (returnCode != LLSEC_MAC_SUCCESS) { + SNI_throwNativeException(returnCode, "LLSEC_MAC_IMPL_reset failed"); + } +} + +/** + * @brief Closes the resources related to the native id. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] native_id The native ID. + * + * @note Throws NativeException on error. + */ +void LLSEC_MAC_IMPL_close(int32_t algorithm_id, int32_t native_id) +{ + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_MAC_algorithm* algorithm = (LLSEC_MAC_algorithm*)algorithm_id; + + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + algorithm->close((void*)native_id); + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + if (SNI_unregisterResource((void*)native_id, (SNI_closeFunction)algorithm->close) != SNI_OK) { + SNI_throwNativeException(-1, "Can't unregister SNI native resource\n"); + } +} +/** + * @brief Gets the id of the native close function. + * + * @param[in] algorithm_id The algorithm ID. + * + * @return the id of the static native close function. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_MAC_IMPL_get_close_id(int32_t algorithm_id) +{ + LLSEC_MAC_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_MAC_algorithm* algorithm = (LLSEC_MAC_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.1 // Abstract data type for SNI usage + return (int32_t)algorithm->close; +} diff --git a/bsp/projects/microej/security/src/LLSEC_PRIVATE_KEY_impl.c b/bsp/projects/microej/security/src/LLSEC_PRIVATE_KEY_impl.c new file mode 100644 index 0000000..02ecf62 --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_PRIVATE_KEY_impl.c @@ -0,0 +1,113 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "mbedtls/platform.h" + + +//#define LLSEC_PRIVATE_KEY_DEBUG + +#ifdef LLSEC_PRIVATE_KEY_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_PRIVATE_KEY_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_PRIVATE_KEY_DEBUG_TRACE(...) ((void)0) +#endif + +/** + * @brief return the max size of the encoded key. + * + * @param[in] native_id the C structure pointer holding the key data + * + * @return max encoded size for the private key in DER format + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_PRIVATE_KEY_IMPL_get_encoded_max_size(int32_t native_id) +{ + LLSEC_PRIVATE_KEY_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_priv_key* key = (LLSEC_priv_key*)native_id; + mbedtls_pk_context pk; + mbedtls_pk_type_t pk_type; + + if (key->type == TYPE_RSA) { + pk_type = MBEDTLS_PK_RSA; + } else { + pk_type = MBEDTLS_PK_ECKEY; + } + + mbedtls_pk_init(&pk); + mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(pk_type)); + pk.pk_ctx = (void*)key->key; + + char buf_local[LLSEC_PRIVATE_KEY_LOCAL_BUFFER_SIZE]; + int length = mbedtls_pk_write_key_der(&pk, (unsigned char*)(&buf_local), sizeof(buf_local)); + + if (length < 0) { + SNI_throwNativeException(-length, "Encoded max size get failed"); + } + + return length; +} + +/** + * @brief encode the private key into DER format. + * + * @param[in] native_id the C structure pointer holding the key data + * @param[out] output a byte array to hold the encoded key data + * @pram[in] outputLength the length of the output array + * + * @return the reel size of the encoded key. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_PRIVATE_KEY_IMPL_get_encode(int32_t native_id, uint8_t* output, int32_t outputLength) +{ + LLSEC_PRIVATE_KEY_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_priv_key* key = (LLSEC_priv_key*)native_id; + mbedtls_pk_context pk; + mbedtls_pk_type_t pk_type; + + if (key->type == TYPE_RSA) { + pk_type = MBEDTLS_PK_RSA; + } else { + pk_type = MBEDTLS_PK_ECKEY; + } + + mbedtls_pk_init(&pk); + mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(pk_type)); + pk.pk_ctx = (void*)key->key; + + //Write a private key to a PKCS#1 or SEC1 DER structure + int length = mbedtls_pk_write_key_der(&pk, output, outputLength); + + if (length < 0) { + SNI_throwNativeException(-1, "DER encoding failed"); + } + + return length; +} diff --git a/bsp/projects/microej/security/src/LLSEC_PUBLIC_KEY_impl.c b/bsp/projects/microej/security/src/LLSEC_PUBLIC_KEY_impl.c new file mode 100644 index 0000000..f775ee8 --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_PUBLIC_KEY_impl.c @@ -0,0 +1,114 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "mbedtls/platform.h" + +//#define LLSEC_PUBLIC_KEY_DEBUG + +#ifdef LLSEC_PUBLIC_KEY_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_PRIVATE_KEY_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_PRIVATE_KEY_DEBUG_TRACE(...) ((void)0) +#endif + +/** + * @brief get max size for encoded key. + * + * @param[in] native_id the C structure pointer holding the key data + * + * @return max encoded size for the public key + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_PUBLIC_KEY_IMPL_get_encoded_max_size(int32_t native_id) +{ + LLSEC_PRIVATE_KEY_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_pub_key* key = (LLSEC_pub_key*)native_id; + + mbedtls_pk_context pk; + mbedtls_pk_type_t pk_type; + + if (key->type == TYPE_RSA) { + pk_type = MBEDTLS_PK_RSA; + } else { + pk_type = MBEDTLS_PK_ECKEY; + } + + mbedtls_pk_init(&pk); + mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(pk_type)); + pk.pk_ctx = (void*)key->key; + + char buf_local[LLSEC_PUBLIC_KEY_LOCAL_BUFFER_SIZE]; + /* Write a public key to a SubjectPublicKeyInfo DER structure */ + int length = mbedtls_pk_write_pubkey_der(&pk, (unsigned char*)(&buf_local), sizeof(buf_local)); + + if (length < 0) { + SNI_throwNativeException(-1, "Encoded key max size get failed"); + } + + return length; +} + +/** + * @brief encode the public key. + * + * @param[in] native_id the C structure pointer holding the key data + * @param[out] output a byte array to hold the encoded key data + * @param[in] outputLength the length of the output array + * + * @return the real size of the encoded key. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_PUBLIC_KEY_IMPL_get_encode(int32_t native_id, uint8_t* output, int32_t outputLength) +{ + LLSEC_PRIVATE_KEY_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_pub_key* key = (LLSEC_pub_key*)native_id; + mbedtls_pk_context pk; + mbedtls_pk_type_t pk_type; + + if (key->type == TYPE_RSA) { + pk_type = MBEDTLS_PK_RSA; + } else { + pk_type = MBEDTLS_PK_ECKEY; + } + + mbedtls_pk_init(&pk); + mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(pk_type)); + pk.pk_ctx = (void*)key->key; + + /*Write a public key to a SubjectPublicKeyInfo DER structure*/ + int length = mbedtls_pk_write_pubkey_der(&pk, output, outputLength); + + if (length < 0) { + SNI_throwNativeException(-1, "Public key encoding failed"); + } + + return length; +} diff --git a/bsp/projects/microej/security/src/LLSEC_RANDOM_impl.c b/bsp/projects/microej/security/src/LLSEC_RANDOM_impl.c new file mode 100644 index 0000000..97f6ff7 --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_RANDOM_impl.c @@ -0,0 +1,256 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include + +#include +#include +#include + +#include "mbedtls/platform.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/entropy.h" + +#define LLSEC_RANDOM_SUCCESS 0 +#define LLSEC_RANDOM_ERROR -1 + +//#define LLSEC_RANDOM_DEBUG + +#ifdef LLSEC_RANDOM_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_RANDOM_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_RANDOM_DEBUG_TRACE(...) ((void)0) +#endif + +static mbedtls_entropy_context entropy; +static mbedtls_ctr_drbg_context ctr_drbg; + +// cppcheck-suppress misra-c2012-8.9 // global variable +static int initialized = 0; +// cppcheck-suppress misra-c2012-8.9 // global variable +static int32_t native_ids = 1; + +/** + * @brief Initializes a Random resource. + * + * @return The native ID of the resource. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_RANDOM_IMPL_init(void) +{ + int32_t return_code = LLSEC_RANDOM_SUCCESS; + LLSEC_RANDOM_DEBUG_TRACE("%s\n", __func__); + const char* pers = llsec_gen_random_str_internal(8); + int32_t native_id; + + if (!initialized) { + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + return_code = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const uint8_t*)pers, 0); + if (return_code != LLSEC_RANDOM_SUCCESS) { + SNI_throwNativeException(return_code, "mbedtls_ctr_drbg_seed failed"); + LLSEC_RANDOM_IMPL_close(0); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_RANDOM_ERROR; + } + initialized = 1; + } + + if (return_code == LLSEC_RANDOM_SUCCESS) { + native_id = native_ids; + native_ids++; + // cppcheck-suppress misra-c2012-11.6 // Cast for matching SNI_registerResource function signature + if (SNI_registerResource((void*)native_id, (SNI_closeFunction)LLSEC_RANDOM_IMPL_close, NULL) != SNI_OK) { + SNI_throwNativeException(LLSEC_RANDOM_ERROR, "Can't register SNI native resource"); + LLSEC_RANDOM_IMPL_close(native_id); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_RANDOM_ERROR; + } + } + + if (return_code == LLSEC_RANDOM_SUCCESS) { + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = native_id; + } + + return return_code; +} + +/** + * @brief Closes the resource related to the nativeId. + * + * @param[in] native_id The native ID. + * + * @note Throws NativeException on error. + */ +void LLSEC_RANDOM_IMPL_close(int32_t native_id) +{ + (void) native_id; // Unused input parameter + LLSEC_RANDOM_DEBUG_TRACE("%s native_id:%d\n", __func__, native_id); + /*To suport multi-instance, do not free the ctr_drbg & entropy here!*/ + //mbedtls_ctr_drbg_free(&ctr_drbg); + //mbedtls_entropy_free(&entropy); +} + +/** + * @brief Generates random bytes. + * + * @param[in] native_id The native ID. + * @param[out] rnd The buffer to fill with random bytes. + * @param[in] size The size of rnd. + * + * @note Throws NativeException on error. + */ +void LLSEC_RANDOM_IMPL_next_bytes(int32_t native_id, uint8_t* rnd, int32_t size) +{ + (void) native_id; // Unused input parameter + + LLSEC_RANDOM_DEBUG_TRACE("%s rdn:0x%p, %d\n", __func__, rnd, size); + uint32_t bytes_left = size; + int32_t result; + while (bytes_left > (uint32_t)0) { + if (bytes_left > MBEDTLS_CTR_DRBG_MAX_REQUEST) { + result = mbedtls_ctr_drbg_random(&ctr_drbg, rnd, MBEDTLS_CTR_DRBG_MAX_REQUEST); + bytes_left -= MBEDTLS_CTR_DRBG_MAX_REQUEST; + // cppcheck-suppress misra-c2012-17.8 // Used as an output parameter + rnd = &rnd[MBEDTLS_CTR_DRBG_MAX_REQUEST]; + } else { + result = mbedtls_ctr_drbg_random(&ctr_drbg, rnd, bytes_left); + bytes_left = 0; + } + if (0 != result) { + SNI_throwNativeException(result, "mbedtls_ctr_drbg_random failed"); + } + } +} + +/** + * @brief Sets the seed of the PRNG. + * + * @param[in] native_id The native ID. + * @param[in] seed The array of bytes used as a seed. + * @param[in] size The size of seed. + * + * @note Throws NativeException on error. + */ +void LLSEC_RANDOM_IMPL_set_seed(int32_t native_id, uint8_t* seed, int32_t size) +{ + (void) native_id; // Unused input parameter + + LLSEC_RANDOM_DEBUG_TRACE("%s\n", __func__); + LLSEC_RANDOM_DEBUG_TRACE("LLSEC_RANDOM_IMPL_set_seed, Seeding the random number generator\n"); + int32_t ret; + + /* + * Since ctr_drbg is not freed (to support multi-instance), setting a new seed from application point of view can be done after mbedtls_ctr_drbg_random calls, + * which will increase the reseed counter with every call, making the entropy nonce length higher than the maximum seed length (MBEDTLS_CTR_DRBG_MAX_SEED_INPUT), + * thus faling to proper set a new seed. + * So, need to reseed first to obtain appropriate entropy nonce length. + */ + ret = mbedtls_ctr_drbg_reseed(&ctr_drbg, NULL, 0); + if (ret != 0) { + SNI_throwNativeException(ret, "mbedtls_ctr_drbg_reseed failed"); + } + + ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char*)seed, size); + if (ret != 0) { + SNI_throwNativeException(ret, "mbedtls_ctr_drbg_seed failed"); + } +} + +/** + * @brief Generates a new seed. + * + * @param[in] native_id The native ID. + * @param[out] seed The array to fill with the seed. + * @param[in] size The size of seed. + * + * @note Throws NativeException on error. + */ + +void LLSEC_RANDOM_IMPL_generate_seed(int32_t native_id, uint8_t* seed, int32_t size) +{ + LLSEC_RANDOM_DEBUG_TRACE("%s\n", __func__); + LLSEC_RANDOM_IMPL_next_bytes(native_id, seed, size); +} + +/** + * @brief Gets the id of the native close function. + * + * @return the id of the static native close function. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_RANDOM_IMPL_get_close_id(void) +{ + LLSEC_RANDOM_DEBUG_TRACE("%s\n", __func__); + return (int32_t) LLSEC_RANDOM_IMPL_close; +} + +/** + * @brief generate random string function. + * @param[in] length the string length + * + * @return pointer of random string. + * + * @note This function should only be used to provide a personalisation string + * when calling mbedtls_ctr_drbg_seed. + */ +char* llsec_gen_random_str_internal(int length) +{ + char* return_code = NULL; + char* strRan; + strRan = (char*)mbedtls_calloc(1, length); + if (NULL == strRan) { + LLSEC_RANDOM_DEBUG_TRACE("Random string malloc failed"); + } else { + srand((unsigned int)time(NULL)); + + int idx; + for (idx = 0; idx < (length - 1); idx++) { + int flag = rand() % 3; + switch (flag) { + case 0: + // cppcheck-suppress misra-c2012-10.8 // Number in [0, 25] range + strRan[idx] = 'A' + (uint8_t)(rand() % 26); + break; + case 1: + // cppcheck-suppress misra-c2012-10.8 // Number in [0, 25] range + strRan[idx] = 'a' + (uint8_t)(rand() % 26); + break; + case 2: + // cppcheck-suppress misra-c2012-10.8 // Number in [0, 10] range + strRan[idx] = '0' + (uint8_t)(rand() % 10); + break; + default: + strRan[idx] = 'x'; + break; + } + } + strRan[length - 1] = '\0'; + return_code = strRan; + } + + return return_code; +} diff --git a/bsp/projects/microej/security/src/LLSEC_SIG_impl.c b/bsp/projects/microej/security/src/LLSEC_SIG_impl.c new file mode 100644 index 0000000..56dfb72 --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_SIG_impl.c @@ -0,0 +1,425 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include +#include +#include +#include +// cppcheck-suppress misra-c2012-21.10 // Type defined in library used in mbedtls +#include + +#include "LLSEC_mbedtls.h" +#include "mbedtls/platform.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/entropy.h" +#include "mbedtls/error.h" +#include "mbedtls/md.h" +#include "mbedtls/pk.h" + +#define LLSEC_SIG_SUCCESS 0 +#define LLSEC_SIG_ERROR -1 + +//#define LLSEC_SIG_DEBUG + +#ifdef LLSEC_SIG_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_SIG_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_SIG_DEBUG_TRACE(...) ((void)0) +#endif + +typedef struct LLSEC_SIG_algorithm LLSEC_SIG_algorithm; +typedef int (*LLSEC_SIG_verify)(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t signature_length, LLSEC_pub_key* pub_key, uint8_t* digest, int32_t digest_length); +typedef int (*LLSEC_SIG_sign)(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t* signature_length, LLSEC_priv_key* priv_key, uint8_t* digest, int32_t digest_length); + +struct LLSEC_SIG_algorithm { + char* name; + char* digest_name; + char* digest_native_name; + char* oid; + LLSEC_SIG_verify verify; + LLSEC_SIG_sign sign; +}; + +static int LLSEC_SIG_mbedtls_verify(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t signature_length, LLSEC_pub_key* pub_key, uint8_t* digest, int32_t digest_length); +static int LLSEC_SIG_mbedtls_sign(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t* signature_length, LLSEC_priv_key* priv_key, uint8_t* digest, int32_t digest_length); + +static int LLSEC_SIG_mbedtls_ec_verify(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t signature_length, LLSEC_pub_key* pub_key, uint8_t* digest, int32_t digest_length); +static int LLSEC_SIG_mbedtls_ec_sign(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t* signature_length, LLSEC_priv_key* priv_key, uint8_t* digest, int32_t digest_length); + +static LLSEC_SIG_algorithm available_sig_algorithms[2] = { + { + .name = "SHA256withRSA", + .digest_name = "SHA-256", + .digest_native_name = "SHA256", + .oid = "1.2.840.113549.1.1.11", + .verify = LLSEC_SIG_mbedtls_verify, + .sign = LLSEC_SIG_mbedtls_sign + }, + { + .name = "SHA256withECDSA", + .digest_name = "SHA-256", + .digest_native_name = "SHA256", + .oid = "1.2.840.10045.4.3.2", + .verify = LLSEC_SIG_mbedtls_ec_verify, + .sign = LLSEC_SIG_mbedtls_ec_sign + } +}; + +static int LLSEC_SIG_mbedtls_ec_verify(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t signature_length, LLSEC_pub_key* pub_key, uint8_t* digest, int32_t digest_length) +{ + (void) algorithm; // Unused input parameter + + LLSEC_SIG_DEBUG_TRACE("%s \n", __func__); + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char* pers = llsec_gen_random_str_internal(8); + + int return_code = LLSEC_SIG_ERROR; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + return_code = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char*)pers, + strlen(pers)); + if (return_code != LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_SIG_ERROR; + } + + if (return_code == LLSEC_SIG_SUCCESS) { + mbedtls_ecdsa_context* ctx = (mbedtls_ecdsa_context*)pub_key->key; + return_code = mbedtls_ecdsa_read_signature(ctx, digest, (size_t)digest_length, + signature, signature_length); + if (return_code != LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_SIG_ERROR; + } + } + + if (return_code == LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + } + return return_code; +} + +static int LLSEC_SIG_mbedtls_ec_sign(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t* signature_length, LLSEC_priv_key* priv_key, uint8_t* digest, int32_t digest_length) +{ + (void) algorithm; // Unused input parameter + + LLSEC_SIG_DEBUG_TRACE("%s \n", __func__); + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char* pers = llsec_gen_random_str_internal(8); + + int return_code = LLSEC_SIG_ERROR; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + return_code = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char*)pers, + strlen(pers)); + + if (return_code != LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_SIG_ERROR; + } + + if (return_code == LLSEC_SIG_SUCCESS) { + mbedtls_ecdsa_context* ctx = (mbedtls_ecdsa_context*)priv_key->key; + return_code = mbedtls_ecdsa_write_signature(ctx, MBEDTLS_MD_SHA256, + digest, (size_t)digest_length, + // cppcheck-suppress misra-c2012-11.3 // Cast for matching mbedtls_ecdsa_write_signature function signature + signature, (size_t*)signature_length, + mbedtls_ctr_drbg_random, &ctr_drbg); + if (return_code != LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_SIG_ERROR; + } + } + + if (return_code == LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + } + + return LLSEC_SIG_SUCCESS; +} + +static int LLSEC_SIG_mbedtls_verify(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t signature_length, LLSEC_pub_key* pub_key, uint8_t* digest, int32_t digest_length) +{ + (void) algorithm; // Unused input parameter + (void) signature_length; // Unused input parameter + + LLSEC_SIG_DEBUG_TRACE("%s \n", __func__); + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char* pers = llsec_gen_random_str_internal(8); + + int return_code = LLSEC_SIG_ERROR; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + return_code = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char*)pers, + strlen(pers)); + if (return_code != LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_SIG_ERROR; + } + + if (return_code == LLSEC_SIG_SUCCESS) { + return_code = mbedtls_rsa_pkcs1_verify((mbedtls_rsa_context*)pub_key->key, + mbedtls_ctr_drbg_random, &ctr_drbg, + MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, + digest_length, digest, signature); + if (return_code != 0) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_SIG_ERROR; + } + } + + if (return_code == LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + } + + return return_code; +} + +static int LLSEC_SIG_mbedtls_sign(LLSEC_SIG_algorithm* algorithm, uint8_t* signature, int32_t* signature_length, LLSEC_priv_key* priv_key, uint8_t* digest, int32_t digest_length) +{ + (void) algorithm; // Unused input parameter + + LLSEC_SIG_DEBUG_TRACE("%s \n", __func__); + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char* pers = llsec_gen_random_str_internal(8); + + int return_code = LLSEC_SIG_ERROR; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + return_code = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char*)pers, + strlen(pers)); + if (return_code != LLSEC_SIG_SUCCESS) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_SIG_ERROR; + } + + if (return_code == LLSEC_SIG_SUCCESS) { + return_code = mbedtls_rsa_pkcs1_sign((mbedtls_rsa_context*)priv_key->key, + mbedtls_ctr_drbg_random, &ctr_drbg, + MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256, + digest_length, digest, signature); + if (return_code != 0) { + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + return_code = LLSEC_SIG_ERROR; + } + } + + if (return_code == LLSEC_SIG_SUCCESS) { + * signature_length = ((mbedtls_rsa_context*)priv_key->key)->len; + + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + // cppcheck-suppress misra-c2012-11.8 // Cast for matching free function signature + mbedtls_free((void*)pers); + } + + return return_code; +} + +/** + * @brief Gets for the given algorithm the message digest description. + * + * @param[in] algorithm_name Null terminated string that describes the algorithm. + * @param[out] digest_algorithm_name Null terminated string that describes the digest algorithm. + * @param[in] digest_algorithm_name_length Length of digest_algorithm. + * + * @return The algorithm ID on success or -1 on error. + * + * @warning algorithm_name must not be used outside of the VM task or saved. + */ +int32_t LLSEC_SIG_IMPL_get_algorithm_description(uint8_t* algorithm_name, uint8_t* digest_algorithm_name, int32_t digest_algorithm_name_length) +{ + int32_t return_code; + LLSEC_SIG_DEBUG_TRACE("%s \n", __func__); + + int32_t nb_algorithms = sizeof(available_sig_algorithms) / sizeof(LLSEC_SIG_algorithm); + LLSEC_SIG_algorithm* algorithm = &available_sig_algorithms[0]; + + while (--nb_algorithms >= 0) { + if (strcmp((char*)algorithm_name, algorithm->name) == 0) { + (void) strncpy((char*)digest_algorithm_name, algorithm->digest_name, digest_algorithm_name_length); + /* strncpy result may not be null-terminated. */ + digest_algorithm_name[digest_algorithm_name_length - 1] = '\0'; + break; + } + algorithm++; + } + + if (nb_algorithms >= 0) { + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + return_code = (int32_t)algorithm; + } else { + return_code = LLSEC_SIG_ERROR; + } + return return_code; +} + +void LLSEC_SIG_IMPL_get_algorithm_oid(uint8_t* algorithm_name, uint8_t* oid, int32_t oid_length) +{ + LLSEC_SIG_DEBUG_TRACE("%s \n", __func__); + + int32_t nb_algorithms = sizeof(available_sig_algorithms) / sizeof(LLSEC_SIG_algorithm); + LLSEC_SIG_algorithm* algorithm = &available_sig_algorithms[0]; + + while (--nb_algorithms >= 0) { + if (strcmp((char*)algorithm_name, algorithm->name) == 0) { + int32_t length = strlen(algorithm->oid); + if ((length + 1) > oid_length) { + SNI_throwNativeException(-1, "Native oid length is bigger that the output byte array"); + } + (void) strncpy((char*)oid, algorithm->oid, length); + /* strncpy result may not be null-terminated. */ + oid[length + 1] = '\0'; + break; + } + algorithm++; + } + if (nb_algorithms < 0) { + /* Algorithm not found. */ + SNI_throwNativeException(LLSEC_SIG_ERROR, "Algorithm not found"); + } +} + +/** + * @brief Verifies a message. + * + * @param[in] algorithm_id The algorithm ID. + * @param[in] signature The buffer containing the signature. + * @param[in] signature_length The signature length. + * @param[in] key The public key. + * @param[in] key_length The key length. + * @param[in] digest The digest of the message to verify. + * @param[in] digest_length The digest length. + * + * @return JTRUE if the signature is valid, JFALSE otherwise. + * + * @note Throws NativeException on error. + * + * @warning signature must not be used outside of the VM task or saved. + * @warning key must not be used outside of the VM task or saved. + * @warning digest must not be used outside of the VM task or saved. + * + */ +uint8_t LLSEC_SIG_IMPL_verify(int32_t algorithm_id, uint8_t* signature, int32_t signature_length, int32_t public_key_id, uint8_t* digest, int32_t digest_length) +{ + uint8_t return_code = JTRUE; + LLSEC_SIG_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_SIG_algorithm* algorithm = (LLSEC_SIG_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + int rc = algorithm->verify(algorithm, signature, signature_length, (LLSEC_pub_key*)public_key_id, digest, digest_length); + + if (rc != LLSEC_SIG_SUCCESS) { + SNI_throwNativeException(rc, "LLSEC_SIG_IMPL_verify failed"); + return_code = JFALSE; + } + return return_code; +} + +/** + * @brief Signs a message. + * + * @param[in] algorithm_id The algorithm ID. + * @param[out] signature The buffer containing the signature. + * @param[in] signature_length The signature length. + * @param[in] key The private key. + * @param[in] key_length The key length. + * @param[in] digest The digest of the message to sign. + * @param[in] digest_length The digest length. + * + * @return The length of the signature. + * + * @note Throws NativeException on error. + * + * @warning signature must not be used outside of the VM task or saved. + * @warning key must not be used outside of the VM task or saved. + * @warning digest must not be used outside of the VM task or saved. + * + */ +int32_t LLSEC_SIG_IMPL_sign(int32_t algorithm_id, uint8_t* signature, int32_t signature_length, int32_t private_key_id, uint8_t* digest, int32_t digest_length) +{ + int32_t return_code = JFALSE; + LLSEC_SIG_DEBUG_TRACE("%s \n", __func__); + + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_SIG_algorithm* algorithm = (LLSEC_SIG_algorithm*)algorithm_id; + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + int rc = algorithm->sign(algorithm, signature, &signature_length, (LLSEC_priv_key*)private_key_id, digest, digest_length); + + if (rc != LLSEC_SIG_SUCCESS) { + SNI_throwNativeException(rc, "LLSEC_SIG_IMPL_sign failed"); + } else { + return_code = signature_length; + } + + return return_code; +} diff --git a/bsp/projects/microej/security/src/LLSEC_X509_CERT_impl.c b/bsp/projects/microej/security/src/LLSEC_X509_CERT_impl.c new file mode 100644 index 0000000..041c973 --- /dev/null +++ b/bsp/projects/microej/security/src/LLSEC_X509_CERT_impl.c @@ -0,0 +1,315 @@ +/* + * C + * + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ Security low level API implementation for MbedTLS Library. + * @author MicroEJ Developer Team + * @version 1.1.0 + */ + +#include +#include +#include +#include + +#include "LLSEC_mbedtls.h" +#include "mbedtls/platform.h" +#include "mbedtls/ssl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LLSEC_X509_SUCCESS 0 +#define LLSEC_X509_ERROR -1 + +#define LLSEC_X509_UNKNOWN_FORMAT (int)(-1) + +//#define LLSEC_X509_DEBUG + +#ifdef LLSEC_X509_DEBUG +// cppcheck-suppress misra-c2012-21.6 // Include only in debug +#include +#define LLSEC_X509_DEBUG_TRACE(...) (void)PRINTF(__VA_ARGS__) +#else +#define LLSEC_X509_DEBUG_TRACE(...) ((void)0) +#endif + +static mbedtls_x509_crt* get_x509_certificate(int8_t* cert_data, int32_t len, int* cert_format); +static int32_t LLSEC_X509_CERT_mbedtls_close_key(int32_t native_id); + +static mbedtls_x509_crt* get_x509_certificate(int8_t* cert_data, int32_t len, int* cert_format) +{ + LLSEC_X509_DEBUG_TRACE("%s 00. cert_len:%d\n", __func__, len); + + mbedtls_x509_crt* tmp_cert = NULL; + int ret = 0; + + /* Allocate a new X509 certificate */ + tmp_cert = (mbedtls_x509_crt*)mbedtls_calloc(1, sizeof(mbedtls_x509_crt)); + if (tmp_cert == NULL) { + if (cert_format != NULL) { + *cert_format = J_MEMORY_ERROR; + } + } + + if (tmp_cert != NULL){ + /* Initialize the X509 certificate */ + mbedtls_x509_crt_init(tmp_cert); + + /* Parse the X509 DER certificate */ + ret = mbedtls_x509_crt_parse_der(tmp_cert, (const uint8_t*)cert_data, len); + if (ret == 0) { + /* Encoded DER certificate */ + if (cert_format != NULL) { + *cert_format = CERT_DER_FORMAT; + } + } else { + LLSEC_X509_DEBUG_TRACE("%s. mbedtls_x509_crt_parse_der fail, ret: %d\n", __func__, ret); + } + } + + if ((tmp_cert != NULL)){ + /*Parse the X509 PEM certificate*/ + mbedtls_x509_crt_init(tmp_cert); + + /*To avoid tmp_cert_data is not a string, which causes mbedtls_x509_crt_parse error*/ + int8_t* tmp_cert_data = (int8_t*)mbedtls_calloc(1, len + 1); + (void) memcpy(tmp_cert_data, cert_data, len); + tmp_cert_data[len] = '\0'; + + /* Parse the X509 PEM certificate */ + ret = mbedtls_x509_crt_parse(tmp_cert, (const uint8_t*)tmp_cert_data, len + 1); + mbedtls_free(tmp_cert_data); + + if (ret == 0) { + /* Encoded PEM certificate */ + if (cert_format != NULL) { + *cert_format = CERT_PEM_FORMAT; + } + } else { + LLSEC_X509_DEBUG_TRACE("%s. mbedtls_x509_crt_parse(PEM) fail, ret: %d\n", __func__, ret); + } + } + + if ((tmp_cert != NULL) && (ret != 0)){ + /*certificate is not PEM/DER*/ + if (cert_format != NULL) { + *cert_format = J_CERT_PARSE_ERROR; + } + } + return tmp_cert; +} + + +static int32_t LLSEC_X509_CERT_mbedtls_close_key(int32_t native_id) +{ + LLSEC_X509_DEBUG_TRACE("%s \n", __func__); + // cppcheck-suppress misra-c2012-11.4 // Abstract data type for SNI usage + LLSEC_pub_key* key = (LLSEC_pub_key*)native_id; + + if (key->type == TYPE_RSA) { + mbedtls_rsa_free((mbedtls_rsa_context*)key->key); + } else { + mbedtls_ecdsa_free((mbedtls_ecdsa_context*)key->key); + } + + mbedtls_free(key); + return LLSEC_X509_SUCCESS; +} + +int32_t LLSEC_X509_CERT_IMPL_parse(int8_t* cert, int32_t off, int32_t len) +{ + LLSEC_X509_DEBUG_TRACE("%s(cert=%p, off=%d, len=%d)\n", __func__, cert, (int)off, (int)len); + + int32_t format = LLSEC_X509_UNKNOWN_FORMAT; + int8_t* cert_data = &cert[off]; + mbedtls_x509_crt* tmp_cert = get_x509_certificate(cert_data, len, &format); + + /* Free the X509 certificate */ + if (tmp_cert != NULL) { + mbedtls_x509_crt_free(tmp_cert); + mbedtls_free((void*)tmp_cert); + } + + return format; +} + +/** + * + * @param cert + * @param certLen + * @param keyData + * @param keyDataLength inparameter. Contains the length of keyData. + * @return the number of bytes copied into keyData + * + ** Warning: cert_data must not be used outside of the VM task or saved + ** Warning: key must not be used outside of the VM task or saved + * + * @throws NativeException on error. + */ +int32_t LLSEC_X509_CERT_IMPL_get_x500_principal_data(int8_t* cert_data, int32_t cert_data_length, uint8_t* principal_data, int32_t principal_data_length, uint8_t get_issuer) +{ + int32_t return_code = LLSEC_X509_SUCCESS; + LLSEC_X509_DEBUG_TRACE("%s(cert=%p, Cert_len=%d,prin_len=%d,get_issuer=%d)\n", __func__, cert_data, (int)cert_data_length, (int)principal_data_length, (int)get_issuer); + + mbedtls_x509_crt* x509 = get_x509_certificate(cert_data, cert_data_length, NULL); + if (x509 == NULL) { + SNI_throwNativeException(LLSEC_X509_ERROR, "Bad x509 certificate"); + return_code = LLSEC_X509_ERROR; + } + + if( return_code == LLSEC_X509_SUCCESS) { + int len; + char buf[256]; + if (get_issuer!= (uint8_t) 0) { + len = mbedtls_x509_dn_gets(buf, sizeof(buf), &(x509->issuer)); + } else { + len = mbedtls_x509_dn_gets(buf, sizeof(buf), &(x509->subject)); + } + + if (len > principal_data_length) { + SNI_throwNativeException(LLSEC_X509_ERROR, "Principal data buffer is too small"); + return_code = LLSEC_X509_ERROR; + } else { + (void) memcpy(principal_data, &buf[0], len); + + /* Free the X509 certificate */ + mbedtls_x509_crt_free(x509); + + return_code = len; + } + } + + return return_code; +} + +/** + * + * @param cert + * @param certLen + * @param keyData + * @param keyDataLength inparameter. Contains the length of keyData. + * @return the number of bytes copied into keyData + * + ** Warning: cert_data must not be used outside of the VM task or saved + ** Warning: key must not be used outside of the VM task or saved + * + * @throws NativeException on error. + */ +int32_t LLSEC_X509_CERT_IMPL_get_key(int8_t* cert_data, int32_t cert_data_length) +{ + int32_t return_code = LLSEC_X509_SUCCESS; + LLSEC_X509_DEBUG_TRACE("%s(cert=%p, len=%d)\n", __func__, cert_data, (int)cert_data_length); + LLSEC_pub_key* pub_key = (LLSEC_pub_key*)mbedtls_calloc(1, sizeof(LLSEC_pub_key)); + mbedtls_x509_crt* x509 = NULL; + void* native_id = NULL; + + if (pub_key == NULL) { + SNI_throwNativeException(LLSEC_X509_ERROR, "Can't allocate LLSEC_pub_key structure"); + return_code = LLSEC_X509_ERROR; + } + + if( return_code == LLSEC_X509_SUCCESS) { + x509 = get_x509_certificate(cert_data, cert_data_length, NULL); + + if (x509 == NULL) { + mbedtls_free(pub_key); + SNI_throwNativeException(LLSEC_X509_ERROR, "Bad x509 certificate"); + + return_code = LLSEC_X509_ERROR; + } + } + + if( return_code == LLSEC_X509_SUCCESS) { + //Note:key TYPE: mbedtls_rsa_context or mbedtls_ecdsa_context + if (mbedtls_pk_get_type(&x509->pk) == MBEDTLS_PK_RSA) { + pub_key->type = TYPE_RSA; + pub_key->key = (char*)mbedtls_pk_rsa(x509->pk); + } else { + pub_key->type = TYPE_ECDSA; + pub_key->key = (char*)mbedtls_pk_ec(x509->pk); + } + + if (pub_key->key == NULL) { + mbedtls_x509_crt_free(x509); + mbedtls_free(pub_key); + + SNI_throwNativeException(LLSEC_X509_ERROR, "Invalid public key from x509 certificate"); + return_code = LLSEC_X509_ERROR; + } + } + + if( return_code == LLSEC_X509_SUCCESS) { + native_id = (void*)pub_key; + if (SNI_registerResource(native_id, (SNI_closeFunction)LLSEC_X509_CERT_mbedtls_close_key, NULL) != SNI_OK) { + SNI_throwNativeException(LLSEC_X509_ERROR, "Can't register SNI native resource"); + + if (pub_key->type == TYPE_RSA) { + mbedtls_rsa_free((mbedtls_rsa_context*)pub_key->key); + } else { + mbedtls_ecdsa_free((mbedtls_ecdsa_context*)pub_key->key); + } + + mbedtls_x509_crt_free(x509); + mbedtls_free(pub_key); + return_code = LLSEC_X509_ERROR; + } + } + + if( return_code == LLSEC_X509_SUCCESS) { + // cppcheck-suppress misra-c2012-11.6 // Abstract data type for SNI usage + return_code = (uint32_t)native_id; + } + + return return_code; +} + +int32_t LLSEC_X509_CERT_IMPL_verify(int8_t* cert_data, int32_t cert_data_length, int32_t public_key_id) +{ + (void) public_key_id; // Unused input parameter + + LLSEC_X509_DEBUG_TRACE("%s \n", __func__); + int return_code = LLSEC_X509_ERROR; + uint32_t flags; + + mbedtls_x509_crt* x509 = get_x509_certificate(cert_data, cert_data_length, NULL); + if (x509 == NULL) { + SNI_throwNativeException(LLSEC_X509_ERROR, "Bad x509 certificate"); + return_code = LLSEC_X509_ERROR; + } + + if (return_code == LLSEC_X509_SUCCESS){ + return_code = mbedtls_x509_crt_verify(x509, NULL, NULL, NULL, &flags, NULL, NULL); + if (return_code != LLSEC_X509_SUCCESS) { + // Error + mbedtls_x509_crt_free(x509); + LLSEC_X509_DEBUG_TRACE("LLSEC_X509 > verify error"); + SNI_throwNativeException(LLSEC_X509_ERROR, "Error x509 verify failed"); + return_code = LLSEC_X509_ERROR; + } + } + + if (return_code == LLSEC_X509_SUCCESS){ + mbedtls_x509_crt_free(x509); + } + return return_code; +} + +/** + * @brief Get the pointer for the close key method to be used as a close resource callback with SNI. + * + * @return the pointer for the close method. + * + * @note Throws NativeException on error. + */ +int32_t LLSEC_X509_CERT_IMPL_get_close_key(void) +{ + LLSEC_X509_DEBUG_TRACE("%s \n", __func__); + return (int32_t)LLSEC_X509_CERT_mbedtls_close_key; +} diff --git a/bsp/projects/microej/ssl/inc/LLNET_SSL_utils_mbedtls.h b/bsp/projects/microej/ssl/inc/LLNET_SSL_utils_mbedtls.h new file mode 100644 index 0000000..8da12f1 --- /dev/null +++ b/bsp/projects/microej/ssl/inc/LLNET_SSL_utils_mbedtls.h @@ -0,0 +1,116 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_SSL_utils_mbedtls functions for mbedtls. + * @author MicroEJ Developer Team + * @version 2.1.6 + * @date 17 January 2023 + */ + +#ifndef LLNET_SSL_UTILS_MBEDTLS +#define LLNET_SSL_UTILS_MBEDTLS + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include "mbedtls/x509_crt.h" +#include "LLNET_SSL_CONSTANTS.h" +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#if !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) +#error "Please set your custom random number generator function in the next #define by replacing my_custom_random_func with the appropriate one. Remove this #error when done." +/* + * Custom random number generator function. + * Used when the platform does not support entropy pool and CTR_DRBG AES-256 random number generator. + * Returns 0 on success, negative value on error. + */ +#define microej_custom_random_func my_custom_random_func +#endif + +#ifdef LLNET_SSL_DEBUG +/* ---- Define the mbedtls debug level ---- */ +#define MBEDTLS_DEBUG_LEVEL 2 + /* ---- Define the mbedtls debug printer ---- */ +#define LLNET_SSL_DEBUG_MBEDTLS_TRACE print_mbedtls_error +#else +#define LLNET_SSL_DEBUG_MBEDTLS_TRACE(...) ((void) 0) +#endif + +/* ---- Specific C Time function ---- */ +/* + * time function to get current JVM application time. + * @param time pointer to time_t struct that will be updated with the current time in seconds + * @return the current time in seconds + */ +time_t custom_mbedtls_time(time_t *time); + +/* ---- Specific net layer connection functions ---- */ + +/* + * Net receive layer adaptation function for mbedtls . + * @param ctx Net context (pointer to the socket fd) + * @param buf buffer for receiving data + * @param len length to receive + * @return -1 on error, number of received bytes otherwise + */ +int LLNET_SSL_utils_mbedtls_recv(void *ctx, unsigned char *buf, size_t len); + +/* + * Net send layer adaptation function for mbedtls . + * @param ctx Net context (pointer to the socket fd) + * @param buf buffer of data to send + * @param len length to send + * @return -1 on error, number of sent bytes otherwise + */ +int LLNET_SSL_utils_mbedtls_send(void *ctx, const unsigned char *buf, size_t len); + +/* ---- mbedtls custom function for error printing ---- */ +void print_mbedtls_error(const char *name, int err); + +/* ---- mbedtls Random Number Generator callback function. ---- */ + +/* + * Random Number Generator (RNG) callback function. + * This function generates a random data. + * If entropy pool and CTR_DRBG AES-256 random number generator are not supported, + * this function uses the custom function microej_custom_random_func for random number generation; + * and this custom function need to be defined in LLNET_SSL_utils_mbedtls.h. + * @param p_rng RNG parameter + * @param output output buffer to fill. + * @param output_len output buffer length. + * @return 0 on success, negative value on error. + */ +int LLNET_SSL_utils_mbedtls_random(void *p_rng, unsigned char *output, size_t output_len); + +/* ---- Parsing certificate helper ---- */ + +/** + * Parse PEM-encoded Certificate. + * PEM certificate content should be null-terminated otherwise mbedtls_x509_crt_parse() method call will fail. + * This method wrap mbedtls_x509_crt_parse() by adding a terminating null byte ('\0') to the certificate data if there is none before calling mbedtls_x509_crt_parse(). + * @param cert the chain to which to add the parsed certificate. + * @param array the buffer holding the certificate data. + * @param offset the offset in the buffer at which the certificate data started. + * @param len the certificate data length. + * + */ +int LLNET_SSL_utils_mbedtls_x509_crt_parse(mbedtls_x509_crt *cert, uint8_t * array, uint32_t offset, uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif //LLNET_SSL_UTILS_MBEDTLS diff --git a/bsp/projects/microej/ssl/inc/LLNET_SSL_verifyCallback.h b/bsp/projects/microej/ssl/inc/LLNET_SSL_verifyCallback.h new file mode 100644 index 0000000..f5315b2 --- /dev/null +++ b/bsp/projects/microej/ssl/inc/LLNET_SSL_verifyCallback.h @@ -0,0 +1,50 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_SSL_verifyCallback functions for mbedtls. + * @author MicroEJ Developer Team + * @version 2.1.6 + * @date 17 January 2023 + */ + +#ifndef LLNET_SSL_VERIFY_CALLBACK +#define LLNET_SSL_VERIFY_CALLBACK + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include "mbedtls/x509.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* + * Verify Callback context +*/ +typedef struct +{ + mbedtls_ssl_config* conf; + uint8_t isUnTrustCA; +}cert_verify_ctx; + + +/* + * Certificate verification callback +*/ +int LLNET_SSL_VERIFY_verifyCallback(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags); + + +#ifdef __cplusplus + } +#endif + +#endif //LLNET_SSL_VERIFY_CALLBACK diff --git a/bsp/projects/microej/ssl/microej_ssl.cmake b/bsp/projects/microej/ssl/microej_ssl.cmake new file mode 100644 index 0000000..065b007 --- /dev/null +++ b/bsp/projects/microej/ssl/microej_ssl.cmake @@ -0,0 +1,11 @@ +include_guard() +message("microej/ssl component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_SSL_CONTEXT_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_SSL_ERRORS.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_SSL_SOCKET_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_SSL_utils_mbedtls.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLNET_SSL_verifyCallback.c +) +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) \ No newline at end of file diff --git a/bsp/projects/microej/ssl/src/LLNET_SSL_CONTEXT_impl.c b/bsp/projects/microej/ssl/src/LLNET_SSL_CONTEXT_impl.c new file mode 100644 index 0000000..473949a --- /dev/null +++ b/bsp/projects/microej/ssl/src/LLNET_SSL_CONTEXT_impl.c @@ -0,0 +1,495 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_SSL_CONTEXT implementation over mbedtls. + * @author MicroEJ Developer Team + * @version 2.1.6 + * @date 17 January 2023 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include "mbedtls/debug.h" +#include "mbedtls/net.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "mbedtls/error.h" +#include "mbedtls/platform.h" +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C) +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#endif +#include "LLNET_SSL_utils_mbedtls.h" +#include "LLNET_SSL_verifyCallback.h" +#include "LLNET_SSL_CONTEXT_impl.h" +#include "LLNET_SSL_CONSTANTS.h" +#include "LLNET_SSL_ERRORS.h" +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + +/* ----------- external function and variables ----------- */ +extern int32_t LLNET_SSL_TranslateReturnCode(int32_t mbedtls_error); +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C) +extern mbedtls_ctr_drbg_context ctr_drbg; +#endif + +/* ----------- Definitions -----------*/ +#define PEM_END "-----END CERTIFICATE-----" + +/* ----------- Private API -----------*/ +#if MBEDTLS_DEBUG_LEVEL > 0 +#include "fsl_debug_console.h" +/** + * Debug callback for mbed TLS + * Just prints on the USB serial port + */ +void microej_mbedtls_debug(void *ctx, int level, const char *file, int line, + const char *str) +{ + const char *p, *basename; + (void) ctx; + + /* Extract basename from file */ + for(p = basename = file; *p != '\0'; p++) { + if(*p == '/' || *p == '\\') { + basename = p + 1; + } + } + + PRINTF("%s:%04d: |%d| %s", basename, line, level, str); +} +#endif + +/* ----------- API -----------*/ + +int32_t LLNET_SSL_CONTEXT_IMPL_createContext(int32_t protocol, uint8_t isClientContext, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(protocol=%d, isClientContext=%d, retry=%d)\n", __func__, (int)protocol, isClientContext, retry); + + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)mbedtls_calloc(1, sizeof(mbedtls_ssl_config)); + void* p_rng = NULL; + if (NULL != conf) + { + mbedtls_ssl_config_init(conf); + + int endpoint; + if (isClientContext) + endpoint = MBEDTLS_SSL_IS_CLIENT; + else + endpoint = MBEDTLS_SSL_IS_SERVER; + + int ret; + if ((ret = mbedtls_ssl_config_defaults(conf, + endpoint, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + (void)ret; + LLNET_SSL_DEBUG_MBEDTLS_TRACE("mbedtls_ssl_config_defaults", ret); + } + + switch (protocol) { + + case SSLv3_PROTOCOL: + mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0 ); + mbedtls_ssl_conf_max_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0 ); + break; + case TLSv1_PROTOCOL: + mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1 ); + mbedtls_ssl_conf_max_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1 ); + break; + case TLSv1_1_PROTOCOL: + mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2 ); + mbedtls_ssl_conf_max_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_2 ); + break; + case TLSv1_2_PROTOCOL: + mbedtls_ssl_conf_min_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3 ); + mbedtls_ssl_conf_max_version(conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3 ); + break; + default: + break; + } + +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C) + p_rng = &ctr_drbg; +#endif + mbedtls_ssl_conf_rng(conf, LLNET_SSL_utils_mbedtls_random, p_rng); + + /* It is possible to disable authentication by passing + * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode() + */ + mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_UNSET); + + /* + * Change certificate verification profile, allocate and initialize new profile + */ + mbedtls_x509_crt_profile* crt_profile = (mbedtls_x509_crt_profile*)mbedtls_calloc(1, sizeof(mbedtls_x509_crt_profile)); + if (NULL == crt_profile){ + mbedtls_ssl_config_free(conf); + mbedtls_free(conf); + return J_CREATE_SSL_CONTEXT_ERROR; + } + /* Hashes from MD5 and above */ + crt_profile->allowed_mds = MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_MD5 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ); + /* Any PK alg */ + crt_profile->allowed_pks = 0xFFFFFFF; + /* Any curve */ + crt_profile->allowed_curves = 0xFFFFFFF; + /* RSA min lenght */ + crt_profile->rsa_min_bitlen = 1024; + + mbedtls_ssl_conf_cert_profile(conf, crt_profile); + + /* Allocate and initialize certificate verify context*/ + cert_verify_ctx* verify_ctx = (cert_verify_ctx*)mbedtls_calloc(1, sizeof(cert_verify_ctx)); + if (NULL == verify_ctx){ + mbedtls_ssl_conf_cert_profile(conf, NULL); + mbedtls_free(crt_profile); + mbedtls_ssl_config_free(conf); + mbedtls_free(conf); + return J_CREATE_SSL_CONTEXT_ERROR; + } + + verify_ctx->conf = conf; + verify_ctx->isUnTrustCA = 0; + + mbedtls_ssl_conf_verify(conf, LLNET_SSL_VERIFY_verifyCallback, (void*)verify_ctx); + +#if MBEDTLS_DEBUG_LEVEL > 0 + mbedtls_ssl_conf_dbg(conf, microej_mbedtls_debug, NULL); +#if defined(MBEDTLS_DEBUG_C) + mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL); +#endif +#endif + + LLNET_SSL_DEBUG_TRACE("%s(method=%d) return ctx=%p\n", __func__, protocol,conf); + + return (int32_t)conf; + } + + return J_CREATE_SSL_CONTEXT_ERROR; //error +} + +int32_t LLNET_SSL_CONTEXT_IMPL_addTrustedCert(int32_t contextID, uint8_t *cert, int32_t off, int32_t len, int32_t format, uint8_t retry){ + + LLNET_SSL_DEBUG_TRACE("%s(context=%d, retry=%d)\n", __func__, (int)contextID, retry); + + int32_t ret = J_SSL_NO_ERROR; + + /* Check parameters */ + if ((NULL == (uint8_t *)(cert + off)) || (0 == len) || + ((CERT_DER_FORMAT != format) && (CERT_PEM_FORMAT != format))) + { + return J_BAD_FUNC_ARG; + } + + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)(contextID); + mbedtls_x509_crt* cacert = NULL; + if (NULL == conf->ca_chain) + { + cacert = (mbedtls_x509_crt*)mbedtls_calloc(1, sizeof(mbedtls_x509_crt)); + mbedtls_x509_crt_init(cacert); + } + else + { + cacert = conf->ca_chain; + } + + if (NULL != conf && NULL != cacert) + { + int ret; + + if (CERT_DER_FORMAT == format) { + ret = mbedtls_x509_crt_parse_der(cacert, (const unsigned char *) (cert + off), len); + ret = LLNET_SSL_TranslateReturnCode(ret); + } else { + /* Find end of first certificate. */ + char* end = strstr((char*) cert, PEM_END); + if (NULL == end) { + ret = J_CREATE_SSL_CONTEXT_ERROR; + } else { + end += sizeof(PEM_END); + int end_index = end - (char*) cert; + ret = LLNET_SSL_utils_mbedtls_x509_crt_parse(cacert, (uint8_t *) cert, off, end_index); + } + } + + if(J_SSL_NO_ERROR != ret){ + mbedtls_free(cacert); + return ret; + } + + if (NULL == conf->ca_chain){ + mbedtls_ssl_conf_ca_chain(conf, cacert, NULL); + } + } + else + { + ret = J_CREATE_SSL_CONTEXT_ERROR; + } + + return ret; +} + + +int32_t LLNET_SSL_CONTEXT_IMPL_clearTrustStore(int32_t contextID, uint8_t retry){ + + LLNET_SSL_DEBUG_TRACE("%s(context=%d, retry=%d)\n", __func__, (int)contextID, retry); + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)(contextID); + + if (NULL != conf) + { + if (NULL != conf->ca_chain) + { + void* chain_ptr = (void*)conf->ca_chain; + mbedtls_ssl_conf_ca_chain(conf, NULL, NULL); + mbedtls_x509_crt_free(chain_ptr); + mbedtls_free(chain_ptr); + } + } + + return J_SSL_NO_ERROR; +} + +int32_t LLNET_SSL_CONTEXT_IMPL_clearKeyStore(int32_t contextID, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(context=%d, retry=%d)\n", __func__, (int)contextID, retry); + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)(contextID); + + /* Free the private key */ + if (NULL != conf) + { + if (NULL != conf->key_cert) + { + if (NULL != conf->key_cert->key) + { + mbedtls_pk_free(conf->key_cert->key); + mbedtls_free(conf->key_cert->key); + } + } + } + + return J_SSL_NO_ERROR; +} + +int32_t LLNET_SSL_CONTEXT_IMPL_setCertificate(int32_t contextID, uint8_t* cert, int32_t offset, int32_t len, int32_t format, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(context=%d, retry=%d)\n", __func__, (int)contextID, retry); + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)(contextID); + mbedtls_x509_crt *clicert; + int ret; + + /* Check parameters */ + if ((NULL == (uint8_t *)((int32_t)cert + offset)) || (0 == len) || + ((CERT_DER_FORMAT != format) && (CERT_PEM_FORMAT != format))) { + return J_BAD_FUNC_ARG; + } + + /* Allocate a new keycert if needed, otherwise free the existing certificate */ + if (NULL == conf->key_cert) { + conf->key_cert = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); + } else { + mbedtls_x509_crt_free(conf->key_cert->cert); + mbedtls_free(conf->key_cert->cert); + } + + if (NULL == conf->key_cert){ + return J_MEMORY_ERROR; + } + + /* The LLNET_SSL_* interface does not support multiple keycert (only one private key can be set) */ + conf->key_cert->next = NULL; + + /* Allocate a new certificate */ + clicert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + if (NULL == clicert){ + return J_MEMORY_ERROR; + } + + /* Try to parse the certificate */ + mbedtls_x509_crt_init(clicert); + if (CERT_DER_FORMAT == format) { + ret = mbedtls_x509_crt_parse_der(clicert, (uint8_t *) ((int32_t)cert + offset), (uint32_t) len); + ret = LLNET_SSL_TranslateReturnCode(ret); + } else { + ret = LLNET_SSL_utils_mbedtls_x509_crt_parse(clicert, (uint8_t *) cert, offset, len); + } + + /* Check parse result */ + if (J_SSL_NO_ERROR != ret) { + /* Free the certificate */ + mbedtls_x509_crt_free(clicert); + mbedtls_free(clicert); + + return J_CERT_PARSE_ERROR; + } + + /* Link the certificate in the keycert */ + conf->key_cert->cert = clicert; + + return J_SSL_NO_ERROR; +} + +int32_t LLNET_SSL_CONTEXT_IMPL_setPrivateKey(int32_t contextID, uint8_t* privateKey, int32_t offset, int32_t len, uint8_t* password, + int32_t passwordOffset, int32_t passwordLen, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(context=%d, retry=%d)\n", __func__, (int)contextID, retry); + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)(contextID); + mbedtls_pk_context *key; + uint8_t * pwd = NULL; + + /* Check parameters */ + if ((NULL == (uint8_t *)((int32_t)privateKey + offset)) || (0 == len)) { + return J_BAD_FUNC_ARG; + } + + /* Check if the password has to be used for decryption */ + if (passwordLen > 0) { + pwd = (uint8_t *) ((int32_t)password + passwordOffset); + } + + /* Allocate a new keycert if needed, otherwise free the existing private key */ + if (NULL == conf->key_cert) { + conf->key_cert = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); + } else { + mbedtls_pk_free(conf->key_cert->key); + mbedtls_free(conf->key_cert->key); + } + + if (NULL == conf->key_cert){ + return J_MEMORY_ERROR; + } + + /* The LLNET_SSL_* interface does not support multiple keycert (only one private key can be set) */ + conf->key_cert->next = NULL; + + /* Allocate a new private key */ + key = mbedtls_calloc( 1, sizeof( mbedtls_pk_context ) ); + if (NULL == key){ + return J_MEMORY_ERROR; + } + + /* Try to parse the private key */ + mbedtls_pk_init(key); + int mbed_err = mbedtls_pk_parse_key(key, + (uint8_t *) ((int32_t)privateKey + offset), (uint32_t) len, + pwd, (uint32_t) passwordLen); + if (0 != mbed_err) { + + print_mbedtls_error(__func__, mbed_err); + /* Free the private key */ + mbedtls_pk_free(key); + mbedtls_free(key); + + return J_NO_PRIVATE_KEY; + } + + /* Link the private key in the keycert */ + conf->key_cert->key = key; + + return J_SSL_NO_ERROR; +} + +int32_t LLNET_SSL_CONTEXT_IMPL_initChainBuffer(int32_t contextID, int32_t nbChainCerts, int32_t chainCertsTotalSize, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(context=%d, nbChainCerts=%d, chainCertsTotalSize=%d, retry=%d)\n", __func__, (int)contextID, (int)nbChainCerts, (int)chainCertsTotalSize, retry); + + return J_SSL_NO_ERROR; +} + +int32_t LLNET_SSL_CONTEXT_IMPL_addChainCertificate(int32_t contextID, uint8_t* cert, int32_t offset, int32_t len, int32_t format, int32_t chainBufferSize, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(context=%d, retry=%d)\n", __func__, (int)contextID, retry); + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)(contextID); + int ret; + + /* Check parameters */ + if ((NULL == (uint8_t *)((int32_t)cert + offset)) || (0 == len) || + ((CERT_DER_FORMAT != format) && (CERT_PEM_FORMAT != format))) { + return J_BAD_FUNC_ARG; + } + + /* Try to parse the certificate, adding it to the chained list of certificated from keycert */ + if (CERT_DER_FORMAT == format) { + ret = mbedtls_x509_crt_parse_der(conf->key_cert->cert, (uint8_t *) ((int32_t)cert + offset), (uint32_t) len); + ret = LLNET_SSL_TranslateReturnCode(ret); + } else { + ret = LLNET_SSL_utils_mbedtls_x509_crt_parse(conf->key_cert->cert, (uint8_t *) cert, offset, len); + } + + /* Check parse result */ + if (J_SSL_NO_ERROR != ret) { + /* Free the certificate */ + mbedtls_x509_crt_free(conf->key_cert->cert); + + return J_CERT_PARSE_ERROR; + } + + return J_SSL_NO_ERROR; +} + +int32_t LLNET_SSL_CONTEXT_IMPL_closeContext(int32_t contextID, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(context=%d, retry=%d)\n", __func__, (int)contextID, retry); + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)(contextID); + + if (NULL != conf) + { + if (NULL != conf->ca_chain) + { + void* chain_ptr = (void*)conf->ca_chain; + mbedtls_ssl_conf_ca_chain(conf, NULL, NULL); + mbedtls_x509_crt_free(chain_ptr); + mbedtls_free(chain_ptr); + } + + if (NULL != conf->p_vrfy) + { + void* vrfy_ptr = (void*)conf->p_vrfy; + mbedtls_ssl_conf_verify(conf, NULL, NULL); + mbedtls_free(vrfy_ptr); + } + + if (NULL != conf->cert_profile) + { + void* profile_ptr = (void*)conf->cert_profile; + mbedtls_ssl_conf_cert_profile(conf, NULL); + mbedtls_free(profile_ptr); + } + + if (NULL != conf->key_cert) + { + if (NULL != conf->key_cert->key) + { + mbedtls_pk_free(conf->key_cert->key); + mbedtls_free(conf->key_cert->key); + } + + if (NULL != conf->key_cert->cert) + { + mbedtls_x509_crt_free(conf->key_cert->cert); + mbedtls_free(conf->key_cert->cert); + } + } + + mbedtls_ssl_config_free(conf); + mbedtls_free((void*)conf); + } + + return J_SSL_NO_ERROR; +} +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/ssl/src/LLNET_SSL_ERRORS.c b/bsp/projects/microej/ssl/src/LLNET_SSL_ERRORS.c new file mode 100644 index 0000000..6222ab0 --- /dev/null +++ b/bsp/projects/microej/ssl/src/LLNET_SSL_ERRORS.c @@ -0,0 +1,414 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_SSL_ERRORS implementation over mbedtls. + * @author MicroEJ Developer Team + * @version 2.1.6 + * @date 17 January 2023 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include "mbedtls/aes.h" +#include "mbedtls/asn1.h" +#include "mbedtls/base64.h" +#include "mbedtls/bignum.h" +#include "mbedtls/blowfish.h" +#include "mbedtls/camellia.h" +#include "mbedtls/ccm.h" +#include "mbedtls/cipher.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/des.h" +#include "mbedtls/dhm.h" +#include "mbedtls/ecp.h" +#include "mbedtls/entropy.h" +#include "mbedtls/gcm.h" +#include "mbedtls/hmac_drbg.h" +#include "mbedtls/md.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/oid.h" +#include "mbedtls/padlock.h" +#include "mbedtls/pem.h" +#include "mbedtls/pk.h" +#include "mbedtls/pkcs12.h" +#include "mbedtls/pkcs5.h" +#include "mbedtls/rsa.h" +#include "mbedtls/ssl.h" +#include "mbedtls/threading.h" +#include "mbedtls/x509.h" +#include "mbedtls/xtea.h" +#include "LLNET_SSL_CONSTANTS.h" +#include "LLNET_SSL_ERRORS.h" +#include "sni.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* -- Mbed TLS unsupported error return */ +/* +J_WINCRYPT_ERROR +J_CRYPTGEN_ERROR +J_RAN_BLOCK_ERROR +J_ISSUER_ERROR +J_ASN_VERSION_ERROR +J_ASN_RSA_KEY_ERROR +J_ASN_OBJECT_ID_ERROR +J_ASN_EXPECT_0_ERROR +J_ASN_BITSTR_ERROR +J_ASN_UNKNOWN_OID_ERROR +J_ASN_DATE_SZ_ERROR +J_ASN_BEFORE_DATE_ERROR +J_ASN_AFTER_DATE_ERROR +J_ASN_SIG_OID_ERROR +J_ASN_TIME_ERROR +J_ASN_SIG_CONFIRM_ERROR +J_ASN_SIG_HASH_ERROR +J_ASN_SIG_KEY_ERROR +J_ASN_DH_KEY_ERROR +J_ASN_NTRU_KEY_ERROR +J_ASN_CRIT_EXT_ERROR +J_ASN_ECC_KEY_ERROR +J_ECC_BAD_ARG_ERROR +J_ECC_CURVE_OID_ERROR +J_ASN_NO_SIGNER_ERROR +J_ASN_CRL_CONFIRM_ERROR +J_ASN_CRL_NO_SIGNER_ERROR +J_ASN_OCSP_CONFIRM_ERROR +J_ALT_NAME_ERROR +J_CAVIUM_INIT_ERROR +J_BAD_ENC_STATE_ERROR +J_REQ_ATTRIBUTE_ERROR +J_PKCS7_OID_ERROR +J_PKCS7_RECIP_ERROR +J_FIPS_NOT_ALLOWED_ERROR +J_ASN_NAME_INVALID_ERROR +J_HMAC_MIN_KEYLEN_ERROR +J_LENGTH_ONLY_ERROR +J_IN_CORE_FIPS_ERROR +J_AES_KAT_FIPS_ERROR +J_DES3_KAT_FIPS_ERROR +J_HMAC_KAT_FIPS_ERROR +J_RSA_KAT_FIPS_ERROR +J_DRBG_KAT_FIPS_ERROR +J_DRBG_CONT_FIPS_ERROR +J_AESGCM_KAT_FIPS_ERROR +J_SIDE_ERROR +J_NO_PEER_KEY +J_VERIFY_MAC_ERROR +J_INCOMPLETE_DATA +J_UNKNOWN_RECORD_TYPE +J_FATAL_ERROR +J_NO_DH_PARAMS +J_BUILD_MSG_ERROR +J_DOMAIN_NAME_MISMATCH +J_NOT_READY_ERROR +J_SERVER_HINT_ERROR +J_PSK_KEY_ERROR +NTRU_KEY_ERROR +J_NTRU_DRBG_ERROR +J_NTRU_ENCRYPT_ERROR +J_NTRU_DECRYPT_ERROR +J_ECC_EXPORT_ERROR +J_ECC_SHARED_ERROR +J_OCSP_CERT_REVOKED +J_CRL_CERT_REVOKED +J_CRL_MISSING +J_OCSP_NEED_URL +J_OCSP_CERT_UNKNOWN +J_OCSP_LOOKUP_FAIL +J_MAX_CHAIN_ERROR +J_SANITY_CIPHER_ERROR +J_OUT_OF_ORDER_ERROR +J_BAD_KEA_TYPE_ERROR +J_RECV_OVERFLOW_ERROR +J_UNKNOWN_HOST_NAME_ERROR +J_KEYUSE_SIGNATURE_ERROR +J_KEYUSE_ENCIPHER_ERROR +J_EXTKEYUSE_AUTH_ERROR +J_SCR_DIFFERENT_CERT_ERROR +J_SEND_OOB_READ_ERROR +J_SANITY_MSG_ERROR +J_DUPLICATE_MSG_ERROR +J_BAD_ENCODED_CERT_FORMAT +J_DECRYPT_ERROR +*/ + + +jint LLNET_SSL_TranslateReturnCode(int32_t mbedtls_error) { + + LLNET_SSL_DEBUG_TRACE("%s(SSL_error=%d)\n", __func__, mbedtls_error); + switch (mbedtls_error) { + + case 0: + return J_SSL_NO_ERROR; + + /* Generic error, no specific error for open */ + case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED: + return J_OPEN_RAN_ERROR; + + case MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR: + return J_READ_RAN_ERROR; + + case MBEDTLS_ERR_RSA_BAD_INPUT_DATA: + return J_RSA_WRONG_TYPE_ERROR; + + case MBEDTLS_ERR_RSA_KEY_GEN_FAILED: + return J_RSA_BUFFER_ERROR; + + case MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE: + return J_BUFFER_ERROR; + + case MBEDTLS_ERR_RSA_VERIFY_FAILED: + return J_ALGO_ID_ERROR; + + case MBEDTLS_ERR_RSA_PUBLIC_FAILED: + return J_PUBLIC_KEY_ERROR; + + + case MBEDTLS_ERR_X509_INVALID_DATE: + return J_DATE_ERROR; + + /* mbedtls have same error for J_SUBJECT_ERROR than J_ISSUER_ERROR*/ + case MBEDTLS_ERR_X509_INVALID_NAME: + return J_SUBJECT_ERROR; + + case MBEDTLS_ERR_X509_INVALID_SIGNATURE: + return J_CA_TRUE_ERROR; + + case MBEDTLS_ERR_X509_INVALID_EXTENSIONS: + return J_EXTENSIONS_ERROR; + + case MBEDTLS_ERR_ASN1_OUT_OF_DATA: + return J_CERT_PARSE_ERROR; + + case MBEDTLS_ERR_ASN1_INVALID_DATA: + return J_ASN_GETINT_ERROR; + + case MBEDTLS_ERR_ASN1_UNEXPECTED_TAG: + return J_ASN_TAG_NULL_ERROR; + + case MBEDTLS_ERR_ASN1_INVALID_LENGTH: + return J_ASN_INPUT_ERROR; + + case MBEDTLS_ERR_MPI_BAD_INPUT_DATA: + case MBEDTLS_ERR_CCM_BAD_INPUT: + case MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA: + case MBEDTLS_ERR_DHM_BAD_INPUT_DATA: + case MBEDTLS_ERR_GCM_BAD_INPUT: + case MBEDTLS_ERR_MD_BAD_INPUT_DATA: + case MBEDTLS_ERR_PEM_BAD_INPUT_DATA: + case MBEDTLS_ERR_PK_BAD_INPUT_DATA: + case MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA: + case MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA: + case MBEDTLS_ERR_THREADING_BAD_INPUT_DATA: + return J_BAD_FUNC_ARG; + + case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE: + return J_NOT_COMPILED_IN; + + case MBEDTLS_ERR_PEM_PASSWORD_MISMATCH: + case MBEDTLS_ERR_PK_PASSWORD_MISMATCH: + case MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH: + case MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH: + return J_UNICODE_SIZE_ERROR; + + case MBEDTLS_ERR_PEM_PASSWORD_REQUIRED: + case MBEDTLS_ERR_PK_PASSWORD_REQUIRED: + return J_NO_PASSWORD; + + case MBEDTLS_ERR_GCM_AUTH_FAILED: + return J_AES_GCM_AUTH_ERROR; + + case MBEDTLS_ERR_CCM_AUTH_FAILED: + return J_AES_CCM_AUTH_ERROR; + + case MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED: + return J_BAD_ALIGN_ERROR; + + case MBEDTLS_ERR_CIPHER_INVALID_PADDING: + return J_BAD_PADDING_ERROR; + + case MBEDTLS_ERR_RSA_RNG_FAILED: + case MBEDTLS_ERR_SSL_NO_RNG: + return J_RNG_FAILURE_ERROR; + + case MBEDTLS_ERR_RSA_INVALID_PADDING: + return J_RSA_PAD_ERROR; + + case MBEDTLS_ERR_SSL_UNKNOWN_CIPHER: + return J_UNSUPPORTED_SUITE; + + case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN: + return J_MATCH_SUITE_ERROR; + + case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH: + case MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH: + case MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH: + case MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG: + case MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH: + case MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG: + case MBEDTLS_ERR_X509_BAD_INPUT_DATA: + case MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH: + return J_INPUT_CASE_ERROR; + + case MBEDTLS_ERR_AES_INVALID_KEY_LENGTH: + case MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH: + case MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH: + return J_PREFIX_ERROR; + + case MBEDTLS_ERR_CIPHER_ALLOC_FAILED: + case MBEDTLS_ERR_DHM_ALLOC_FAILED: + case MBEDTLS_ERR_MD_ALLOC_FAILED: + case MBEDTLS_ERR_X509_ALLOC_FAILED: + case MBEDTLS_ERR_MPI_ALLOC_FAILED: + case MBEDTLS_ERR_ASN1_ALLOC_FAILED: + case MBEDTLS_ERR_ECP_ALLOC_FAILED: + case MBEDTLS_ERR_PK_ALLOC_FAILED: + case MBEDTLS_ERR_SSL_ALLOC_FAILED: + return J_MEMORY_ERROR; + + case MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH: + return J_VERIFY_FINISHED_ERROR; + + case MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO: + return J_HEADER_PARSE_ERROR; + + case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE: + case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST: + case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY: + return J_NO_PEER_CERT; + + case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: + return J_UNKNOWN_HANDSHAKE_TYPE; + + case MBEDTLS_ERR_NET_SOCKET_FAILED: + case MBEDTLS_ERR_NET_CONNECT_FAILED: + case MBEDTLS_ERR_NET_BIND_FAILED: + case MBEDTLS_ERR_NET_LISTEN_FAILED: + case MBEDTLS_ERR_NET_ACCEPT_FAILED: + case MBEDTLS_ERR_NET_SEND_FAILED: + case MBEDTLS_ERR_NET_CONN_RESET: + case MBEDTLS_ERR_NET_UNKNOWN_HOST: + return J_SOCKET_ERROR; + + case MBEDTLS_ERR_NET_RECV_FAILED: + case MBEDTLS_ERR_NET_BUFFER_TOO_SMALL: + case MBEDTLS_ERR_NET_INVALID_CONTEXT: + return J_SOCKET_NODATA; + + case MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG: + case MBEDTLS_ERR_PK_TYPE_MISMATCH: + return J_ENCRYPT_ERROR; + + case MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED: + return J_NO_PRIVATE_KEY; + + case MBEDTLS_ERR_RSA_PRIVATE_FAILED: + return J_RSA_PRIVATE_ERROR; + + case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO: + return J_BAD_HELLO; + + case MBEDTLS_ERR_SSL_WANT_READ: + return J_WANT_READ; + + case MBEDTLS_ERR_SSL_WANT_WRITE: + return J_WANT_WRITE; + + case MBEDTLS_ERR_PK_KEY_INVALID_VERSION: + return J_PMS_VERSION_ERROR; + + case MBEDTLS_ERR_X509_INVALID_VERSION: + case MBEDTLS_ERR_X509_UNKNOWN_VERSION: + return J_VERSION_ERROR; + + case MBEDTLS_ERR_ASN1_BUF_TOO_SMALL: + case MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL: + case MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL: + case MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL: + case MBEDTLS_ERR_OID_BUF_TOO_SMALL: + case MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL: + case MBEDTLS_ERR_X509_BUFFER_TOO_SMALL: + return J_MALFORMED_BUFFER; + + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + return J_VERIFY_CERT_ERROR; + + case MBEDTLS_ERR_X509_SIG_MISMATCH: + return J_VERIFY_SIGN_ERROR; + + case MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY: + return J_CLIENT_ID_ERROR; + + case MBEDTLS_ERR_SSL_BAD_INPUT_DATA: + return J_LENGTH_ERROR; + + case MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE: + return J_PEER_KEY_ERROR; + + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + return J_ZERO_RETURN; + + case MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE: + return J_ECC_CURVETYPE_ERROR; + + case MBEDTLS_ERR_ECP_BAD_INPUT_DATA: + return J_ECC_CURVE_ERROR; + + case MBEDTLS_ERR_ECP_INVALID_KEY: + return J_ECC_PEERKEY_ERROR; + + case MBEDTLS_ERR_ECP_RANDOM_FAILED: + return J_ECC_MAKEKEY_ERROR; + + case MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED: + return J_NO_TRUSTED_CERT; + + case MBEDTLS_ERR_PEM_ALLOC_FAILED: + return J_BAD_CERT_MANAGER_ERROR; + + case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: + return J_SUITES_ERROR; + + case MBEDTLS_ERR_PEM_INVALID_DATA: + return J_SSL_NO_PEM_HEADER; + + case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED: + return J_NO_PEER_VERIFY; + + case MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO: + return J_SECURE_RENEGOTIATION_ERROR; + + case MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC: + return J_NO_CHANGE_CIPHER_ERROR; + + case MBEDTLS_ERR_X509_INVALID_FORMAT : + return J_BAD_CERTTYPE; + + default: + return J_UNKNOWN_ERROR; + } + +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/ssl/src/LLNET_SSL_SOCKET_impl.c b/bsp/projects/microej/ssl/src/LLNET_SSL_SOCKET_impl.c new file mode 100644 index 0000000..98f5b45 --- /dev/null +++ b/bsp/projects/microej/ssl/src/LLNET_SSL_SOCKET_impl.c @@ -0,0 +1,429 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_SSL_SOCKET implementation over mbedtls. + * @author MicroEJ Developer Team + * @version 2.1.6 + * @date 17 January 2023 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include "mbedtls/ssl.h" +#include "mbedtls/net_sockets.h" +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C) +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#endif +#include "mbedtls/platform.h" +#include "LLNET_Common.h" +#include "LLNET_CONSTANTS.h" +#include "LLNET_CHANNEL_impl.h" +#include "LLNET_SSL_ERRORS.h" +#include "LLNET_SSL_utils_mbedtls.h" +#include "LLNET_SSL_SOCKET_impl.h" +#include "LLNET_SSL_CONSTANTS.h" +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/* external functions */ +extern int32_t LLNET_SSL_TranslateReturnCode(int32_t mbedtls_error); + +typedef struct +{ + mbedtls_ssl_context ssl_context; + uint32_t closeNotifyFlag; +} ssl_socket ; + +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C) +/* Global variable for entropy in drbg context */ +mbedtls_ctr_drbg_context ctr_drbg; +static mbedtls_entropy_context entropy; + +/* personalization string for the drbg */ +const char *DRBG_PERS = "mbed TLS microEJ client"; +#endif + +/* static functions */ +static int32_t LLNET_SSL_SOCKET_IMPL_initialHandShake(int32_t sslID, int32_t fd, uint8_t retry); +static int32_t asyncOperationWrapper(int32_t fd, SELECT_Operation operation, uint8_t retry); + +int32_t LLNET_SSL_SOCKET_IMPL_initialize(void){ + LLNET_SSL_DEBUG_TRACE("%s()\n", __func__); + +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C) + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + int ret; + if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, + (const unsigned char *) DRBG_PERS, + sizeof (DRBG_PERS))) != 0) { + LLNET_SSL_DEBUG_MBEDTLS_TRACE("mbedtls_crt_drbg_init", ret); + return LLNET_SSL_TranslateReturnCode(ret); + } +#endif + + return J_SSL_NO_ERROR; +} + +int32_t LLNET_SSL_SOCKET_IMPL_create(int32_t contextID, int32_t fd, uint8_t* hostname, int32_t hostnameLen, uint8_t autoclose, uint8_t useClientMode, uint8_t needClientAuth, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(context=%d, fd=%d, autoclose=%d, useClientMode=%d, needClientAuth=%d, retry=%d)\n", __func__, (int)contextID, (int)fd, autoclose, useClientMode, needClientAuth, retry); + + mbedtls_ssl_config* conf = (mbedtls_ssl_config*)(contextID); + ssl_socket* ssl_ctx = (ssl_socket*)mbedtls_calloc(1, sizeof(ssl_socket)); + + if ( conf != NULL && ssl_ctx != NULL) + { + /* It is possible to disable authentication by passing + * MBEDTLS_SSL_VERIFY_NONE in the call to mbedtls_ssl_conf_authmode() + */ + if (useClientMode || needClientAuth) { + mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_REQUIRED); + } else { + mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE); + } + + mbedtls_ssl_init(&(ssl_ctx->ssl_context)); + if ((NULL != hostname) && (hostnameLen > 0)) { + // Check if the given host is an IP address or is actually a host name. + struct sockaddr_in hostAddr; + int is_valid_addr = inet_pton(AF_INET,(const char*) hostname, &(hostAddr.sin_addr)); + if(0 == is_valid_addr) { + mbedtls_ssl_set_hostname(&(ssl_ctx->ssl_context), (char*)hostname); + } + } + ssl_ctx->closeNotifyFlag = 0; + + int ret = 0; + if ((ret = mbedtls_ssl_setup(&(ssl_ctx->ssl_context), conf)) != 0) { + mbedtls_ssl_free(&(ssl_ctx->ssl_context)); + mbedtls_free((void*)ssl_ctx); + (void)ret; + LLNET_SSL_DEBUG_MBEDTLS_TRACE("mbedtls_ssl_setup", ret); + return J_CREATE_SSL_ERROR; //error + } + + int* net_socket = (int*)mbedtls_calloc(1, sizeof(int)); + if (net_socket != NULL) + { + *(net_socket) = fd; + mbedtls_ssl_set_bio(&(ssl_ctx->ssl_context), (void*)net_socket, LLNET_SSL_utils_mbedtls_send, LLNET_SSL_utils_mbedtls_recv, NULL ); + } + else{ + mbedtls_ssl_free(&(ssl_ctx->ssl_context)); + mbedtls_free((void*)ssl_ctx); + return J_CREATE_SSL_ERROR; + } + } + else + return J_CREATE_SSL_ERROR; + + return (int32_t)ssl_ctx; +} + + +int32_t LLNET_SSL_SOCKET_IMPL_close(int32_t sslID, int32_t fd, uint8_t autoclose, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(ssl=%d, fd=%d, autoclose=%d, retry=%d)\n", __func__, (int)sslID, (int)fd, autoclose, retry); + + ssl_socket* ssl_ctx = (ssl_socket*)(sslID); + + if (ssl_ctx == NULL) + return J_CREATE_SSL_ERROR; + + if(!retry){ + //set non-blocking mode + bool was_non_blocking = is_socket_non_blocking(fd); + int32_t res = 0; + if(was_non_blocking == false){ + res = set_socket_non_blocking(fd, true); + } + + if(res == 0){ + //send close notify + int ret = mbedtls_ssl_close_notify(&(ssl_ctx->ssl_context)); + if (ret < 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + LLNET_SSL_DEBUG_MBEDTLS_TRACE("mbedtls_ssl_close_notify", ret); + } + } + + //reset non-blocking mode + if(was_non_blocking == false){ + res = set_socket_non_blocking(fd, false); + if(res != 0){ + return J_CREATE_SSL_ERROR; + } + } + } else { + return J_CREATE_SSL_ERROR; + } + } + + if(!autoclose){ + //the close of the underlying socket is not requested + //read close_notify alert to clear input stream + int8_t buffer[1]; + int32_t res = LLNET_SSL_SOCKET_IMPL_read(sslID, fd, buffer, 0, 1, retry); + + if(res == J_NATIVE_CODE_BLOCKED_WITHOUT_RESULT || (res >= 0 && !(ssl_ctx->closeNotifyFlag))){ + //read operation does not failed and the close notify alert is not yet received + return J_NATIVE_CODE_BLOCKED_WITHOUT_RESULT; + } + } + + LLNET_SSL_DEBUG_TRACE("%s(ssl=%d, fd=%d, autoclose=%d, retry=%d) free SSL\n", __func__, (int)sslID, (int)fd, (int)autoclose, (int)retry); + + return J_SSL_NO_ERROR; +} + + +int32_t LLNET_SSL_SOCKET_IMPL_freeSSL(int32_t sslID, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(ssl=%d, retry=%d)\n", __func__, (int)sslID, retry); + + ssl_socket* ssl_ctx = (ssl_socket*)(sslID); + + if (ssl_ctx == NULL) + return J_CREATE_SSL_ERROR; + + //free BIO + if (ssl_ctx->ssl_context.p_bio) { + mbedtls_free(ssl_ctx->ssl_context.p_bio); + } + + //free SSL + mbedtls_ssl_free(&(ssl_ctx->ssl_context)); + mbedtls_free((void*)ssl_ctx); + + return J_SSL_NO_ERROR; +} + +int32_t LLNET_SSL_SOCKET_IMPL_initialClientHandShake(int32_t sslID, int32_t fd, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(ssl=%d, fd=%d, retry=%d)\n", __func__, (int)sslID, (int)fd, retry); + + return LLNET_SSL_SOCKET_IMPL_initialHandShake(sslID, fd, retry); +} + +int32_t LLNET_SSL_SOCKET_IMPL_initialServerHandShake(int32_t sslID, int32_t fd, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(ssl=%d, fd=%d, retry=%d)\n", __func__, (int)sslID, (int)fd, retry); + + return LLNET_SSL_SOCKET_IMPL_initialHandShake(sslID, fd, retry); +} + +int32_t LLNET_SSL_SOCKET_IMPL_read(int32_t sslID, int32_t fd, int8_t* buf, int32_t off, int32_t len, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(ssl=%d, fd=%d, offset=%d, length=%d, retry=%d)\n", __func__, (int)sslID, (int)fd, (int)off, (int)len, retry); + + //set non-blocking mode + bool was_non_blocking = is_socket_non_blocking(fd); + int32_t res; + if(was_non_blocking == false){ + res = set_socket_non_blocking(fd, true); + if(res != 0){ + return J_SOCKET_ERROR; + } + } + + ssl_socket* ssl_ctx = (ssl_socket*)(sslID); + if (NULL == ssl_ctx) + return J_CREATE_SSL_ERROR; + + /* Read data out of the socket */ + int ret = mbedtls_ssl_read(&(ssl_ctx->ssl_context), (unsigned char *) buf + off, len); + if (ret < 0) { + if (MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY == ret){ + ssl_ctx->closeNotifyFlag = 1; + //end-of-file + return J_EOF; + } + else if (MBEDTLS_ERR_SSL_WANT_READ != ret && MBEDTLS_ERR_SSL_WANT_WRITE != ret) { + LLNET_SSL_DEBUG_MBEDTLS_TRACE("mbedtls_ssl_read", ret); + } + } + + LLNET_SSL_DEBUG_TRACE("%s READ (ssl=%d, fd=%d, offset=%d, length=%d, retry=%d) bytes read=%d\n", __func__, (int)sslID, (int)fd, (int)off, (int)len, (int)retry, (int)ret); + + //restore original flags + if(was_non_blocking == false){ + res = set_socket_non_blocking(fd, false); + if(res != 0){ + return J_SOCKET_ERROR; + } + } + + if(ret < 0){ + if(ret == MBEDTLS_ERR_SSL_WANT_READ){ + return asyncOperationWrapper(fd, SELECT_READ, retry); + } + else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE){ + //read operation can also cause write operation when the peer requests a re-negotiation + return asyncOperationWrapper(fd, SELECT_WRITE, retry); + } + return LLNET_SSL_TranslateReturnCode(ret); + } + + return ret; +} + +int32_t LLNET_SSL_SOCKET_IMPL_write(int32_t sslID, int32_t fd, int8_t* buf, int32_t off, int32_t len, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(ssl=%d, fd=%d, offset=%d, length=%d, retry=%d)\n", __func__, (int)sslID, (int)fd, (int)off, (int)len, retry); + + //set non-blocking mode + bool was_non_blocking = is_socket_non_blocking(fd); + int32_t res; + if(was_non_blocking == false){ + res = set_socket_non_blocking(fd, true); + if(res != 0){ + return J_SOCKET_ERROR; + } + } + + ssl_socket* ssl_ctx = (ssl_socket*)(sslID); + if (NULL == ssl_ctx) + return J_CREATE_SSL_ERROR; + + int ret = mbedtls_ssl_write(&(ssl_ctx->ssl_context), (const unsigned char *) buf + off, len); + if (ret < 0) { + if (MBEDTLS_ERR_NET_CONN_RESET == ret){ + /* Set ret to 0 for re*/ + return J_CONNECTION_RESET; + } + else if (MBEDTLS_ERR_SSL_WANT_READ != ret && + MBEDTLS_ERR_SSL_WANT_WRITE != ret) { + LLNET_SSL_DEBUG_MBEDTLS_TRACE("mbedtls_ssl_write", ret); + } + } + + LLNET_SSL_DEBUG_TRACE("%s WRITE (ssl=%d, fd=%d, offset=%d, length=%d, retry=%d) written bytes=%d\n", __func__, (int)sslID, (int)fd, (int)off, (int)len, (int)retry, (int)ret); + + //restore original flags + if(was_non_blocking == false){ + res = set_socket_non_blocking(fd, false); + if(res != 0){ + return J_SOCKET_ERROR; + } + } + + if(ret < 0){ + if(ret == MBEDTLS_ERR_SSL_WANT_READ){ + //write operation can also cause read operation when the peer requests a re-negotiation + return asyncOperationWrapper(fd, SELECT_READ, retry); + } + else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE){ + return asyncOperationWrapper(fd, SELECT_WRITE, retry); + } + return LLNET_SSL_TranslateReturnCode(ret); + } + + return ret; +} + +int32_t LLNET_SSL_SOCKET_IMPL_available(int32_t sslID, uint8_t retry){ + LLNET_SSL_DEBUG_TRACE("%s(ssl=%d, retry=%d)\n", __func__, (int)sslID, retry); + + ssl_socket* ssl_ctx = (ssl_socket*)(sslID); + if (NULL == ssl_ctx) + return J_CREATE_SSL_ERROR; + + int ret = (int) mbedtls_ssl_get_bytes_avail( &(ssl_ctx->ssl_context) ); + + if(ret < 0){ + return J_UNKNOWN_ERROR; + } + return ret; +} + +static int32_t LLNET_SSL_SOCKET_IMPL_initialHandShake(int32_t sslID, int32_t fd, uint8_t retry){ + //set non-blocking mode + bool was_non_blocking = is_socket_non_blocking(fd); + int32_t res; + if(was_non_blocking == false){ + res = set_socket_non_blocking(fd, true); + if(res != 0){ + return J_SOCKET_ERROR; + } + } + + ssl_socket* ssl_ctx = (ssl_socket*)(sslID); + if (NULL == ssl_ctx) + return J_CREATE_SSL_ERROR; + + int ret = mbedtls_ssl_handshake(&(ssl_ctx->ssl_context)); + if (ret < 0) { + if (MBEDTLS_ERR_SSL_WANT_READ != ret && + MBEDTLS_ERR_SSL_WANT_WRITE != ret) + { + LLNET_SSL_DEBUG_MBEDTLS_TRACE("mbedtls_ssl_handshake", ret); + + /* Send bad cert alert if no cert available */ + if (MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED == ret){ + int32_t retAlert = 0; + if (0 != (retAlert = mbedtls_ssl_send_alert_message( &(ssl_ctx->ssl_context), + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_BAD_CERT))) + { + printf("ERROR : failed to send alert_message : ret = %d", retAlert); + } + } + + /* SSL Context unusable */ + mbedtls_ssl_session_reset(&(ssl_ctx->ssl_context)); + } + } + + LLNET_SSL_DEBUG_TRACE("%s HandShake (ssl=%d, fd=%d, retry=%d) ret=%d\n", __func__, (int)sslID, (int)fd, (int)retry, (int)ret); + + //restore original flags + if(false == was_non_blocking){ + res = set_socket_non_blocking(fd, false); + if(0 != res){ + return J_SOCKET_ERROR; + } + } + + if(0 != ret){ + if(MBEDTLS_ERR_SSL_WANT_READ == ret){ + return asyncOperationWrapper(fd, SELECT_READ, retry); + } + else if(MBEDTLS_ERR_SSL_WANT_WRITE == ret){ + return asyncOperationWrapper(fd, SELECT_WRITE, retry); + } + + return LLNET_SSL_TranslateReturnCode(ret); + } + + return ret; +} + +static int32_t asyncOperationWrapper(int32_t fd, SELECT_Operation operation, uint8_t retry){ + int32_t ret = asyncOperation(fd, operation, retry); + LLNET_SSL_DEBUG_TRACE("asyncOperation (fd=%d, operation=%s, retry=%d) ret=%d\n", fd, operation == SELECT_READ ? "READ" : "WRITE", retry, ret); + + if (0 == ret){ + return J_NATIVE_CODE_BLOCKED_WITHOUT_RESULT; + } else if (J_ASYNC_BLOCKING_REQUEST_QUEUE_LIMIT_REACHED == ret){ + return J_BLOCKING_QUEUE_LIMIT_REACHED; + } else if (J_ETIMEDOUT == ret){ + return J_SOCKET_TIMEOUT; + } else if (J_EUNKNOWN == ret){ + return J_UNKNOWN_ERROR; + } else { + return ret; + } +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/ssl/src/LLNET_SSL_utils_mbedtls.c b/bsp/projects/microej/ssl/src/LLNET_SSL_utils_mbedtls.c new file mode 100644 index 0000000..cb1c6e6 --- /dev/null +++ b/bsp/projects/microej/ssl/src/LLNET_SSL_utils_mbedtls.c @@ -0,0 +1,252 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_SSL_utils_mbedtls implementation over mbedtls. + * @author MicroEJ Developer Team + * @version 2.1.6 + * @date 17 January 2023 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include "mbedtls/error.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/x509_crt.h" +#if defined(MBEDTLS_CTR_DRBG_C) +#include "mbedtls/ctr_drbg.h" +#endif +#include "mbedtls/platform.h" +#include "LLNET_Common.h" +#include "LLNET_SSL_utils_mbedtls.h" +#include "LLNET_SSL_ERRORS.h" +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + + /* ---- constants ---- */ + + /** + * @brief null terminated character + */ +#define NULL_CHARACTER '\0' + +/* ---- external functions ---- */ +/** + * @brief External function used to retrieve currentTime (defined in LLMJVM) + */ +extern int64_t LLMJVM_IMPL_getCurrentTime__Z(uint8_t system); + +/** + * @brief External function used to map mbedtls error code to MicroEJ SSL error code + */ +extern int32_t LLNET_SSL_TranslateReturnCode(int32_t mbedtls_error); + +/* ---- private functions ---- */ +static uint8_t * microej_get_str_from_array(uint8_t * array, uint32_t offset, uint32_t * len) { + uint8_t * p_str; + + p_str = (uint8_t *) array + offset; + + /* Check if array is null terminated */ + if (NULL_CHARACTER != p_str[*len - 1]) { + int32_t trueLength = SNI_getArrayLength(array) - offset; + + /* len should be one byte longer to store the null terminated key */ + (*len)++; + + /* Check if there is enough space in the byte array to insert a null character */ + if (trueLength > *len) { + p_str[*len - 1] = NULL_CHARACTER; + } else { + /* + * Duplicate the array but with a null terminated character, + * /!\ this new string must be freed + */ + + /* Try first internal memory because it is faster */ + p_str = mbedtls_calloc(1, *len); + + if (NULL == p_str) { + return NULL; + } + + memcpy((void *)p_str, (void *)(array + offset), *len - 1); + p_str[*len - 1] = NULL_CHARACTER; + + } + } + + return (uint8_t *) p_str; +} + +/* ---- Specific C Time function ---- */ + +time_t custom_mbedtls_time(time_t *time) +{ + time_t currentTime = (time_t)(LLMJVM_IMPL_getCurrentTime__Z(0) / 1000); + + if (NULL != time) + { + *time = currentTime; + } + + return currentTime; +} + +/* ---- Specific net layer connection functions ---- */ + +/** + * Receive callback for mbed TLS + */ +int LLNET_SSL_utils_mbedtls_recv(void *ctx, unsigned char *buf, size_t len) { + LLNET_SSL_DEBUG_TRACE("%s(ctx=%d, length=%d)\n", __func__, (int)ctx, (int)len); + int recv_bytes = -1; + + int fd = *((int*)ctx); + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + int32_t selectRes = non_blocking_select( fd, SELECT_READ ); + + if( selectRes == 0 ) { + LLNET_SSL_DEBUG_TRACE("%s RECV WANT READ(ctx=%d, length=%d)\n", __func__, (int)ctx, (int)len); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } else { + recv_bytes = llnet_recv( fd, buf, len, 0 ); + int netError = errno; + + LLNET_SSL_DEBUG_TRACE("%s RECV (ctx=%d, length=%d) bytes read=%d, netError=%d\n", __func__, (int)ctx, (int)len, (int)recv_bytes, (int)netError); + + if( recv_bytes < 0 ) + { + if( netError == EPIPE || netError == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( netError == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + } + + return recv_bytes; +} + +/** + * Send callback for mbed TLS + */ +int LLNET_SSL_utils_mbedtls_send(void *ctx, const unsigned char *buf, size_t len) { + LLNET_SSL_DEBUG_TRACE("%s(ctx=%d, length=%d)\n", __func__, (int)ctx, (int)len); + int size_sent = -1; + + int fd = *((int*)ctx); + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + int32_t selectRes = non_blocking_select( fd, SELECT_WRITE ); + + if( selectRes == 0 ) { + LLNET_SSL_DEBUG_TRACE("%s SEND WANT WRITE(ctx=%d, length=%d)\n", __func__, (int)ctx, (int)len); + return( MBEDTLS_ERR_SSL_WANT_WRITE ); + } else { + size_sent = llnet_send( fd, buf, len, 0 ); + int netError = errno; + + LLNET_SSL_DEBUG_TRACE("%s SEND (ctx=%d, length=%d) bytes read=%d netError=%d\n", __func__, (int)ctx, (int)len, (int)size_sent, (int)netError); + + if( size_sent < 0 ) + { + if( netError == EPIPE || netError == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( netError == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); + + return( MBEDTLS_ERR_NET_SEND_FAILED ); + } + } + + return size_sent; +} + +/* ---- mbedtls custom function for error printing ---- */ +#include "fsl_debug_console.h" +/** + * Helper for pretty-printing mbed TLS error codes + */ + void print_mbedtls_error(const char *name, int err) { + char buf[128]; + mbedtls_strerror(err, buf, sizeof (buf)); + PRINTF("%s() failed: -0x%04x (%d): %s\r\n", name, -err, err, buf); +} + +/* ---- random number generator callback function. ---- */ + +/* + * Random Number Generator (RNG) callback function. + * This function generates a random data. + * If entropy pool and CTR_DRBG AES-256 random number generator are not supported, + * this function uses the custom function microej_custom_random_func for random number generation; + * and this custom function need to be defined in LLNET_SSL_utils_mbedtls.h. + * @param p_rng : RNG parameter + * @param output : output buffer to fill. + * @param output_len : output buffer length. + * @return 0 on success, negative value on error. + */ +int LLNET_SSL_utils_mbedtls_random(void *p_rng, unsigned char *output, size_t output_len) +{ +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C) + return mbedtls_ctr_drbg_random(p_rng, output, output_len); +#else + (void) p_rng; + return microej_custom_random_func(output, output_len); +#endif +} + +/* ---- Parsing certificate helper ---- */ + +/** + * Parse PEM-encoded Certificate. + * PEM certificate content should be null-terminated otherwise mbedtls_x509_crt_parse() method call will fail. + * This method wrap mbedtls_x509_crt_parse() by adding a terminating null byte ('\0') to the certificate data if there is none before calling mbedtls_x509_crt_parse(). + * @param cert : the chain to which to add the parsed certificate. + * @param array : the buffer holding the certificate data. + * @param offset : the offset in the buffer at which the certificate data started. + * @param len : the certificate data length. + * + */ +int LLNET_SSL_utils_mbedtls_x509_crt_parse(mbedtls_x509_crt *cert, uint8_t * array, uint32_t offset, uint32_t len) { + LLNET_SSL_DEBUG_TRACE("%s()\n", __func__); + uint8_t * strCert = microej_get_str_from_array(array, offset, &len); + + if (NULL == strCert) { + return J_MEMORY_ERROR; + } + + int ret = mbedtls_x509_crt_parse(cert, strCert, (uint32_t) len); + + // Free strCert if it has been allocated by microej_get_str_from_array + if (strCert != (array + offset)) { + free(strCert); + } + + return LLNET_SSL_TranslateReturnCode(ret); +} + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/ssl/src/LLNET_SSL_verifyCallback.c b/bsp/projects/microej/ssl/src/LLNET_SSL_verifyCallback.c new file mode 100644 index 0000000..99a60c5 --- /dev/null +++ b/bsp/projects/microej/ssl/src/LLNET_SSL_verifyCallback.c @@ -0,0 +1,123 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief LLNET_SSL_verifyCallback implementation over mbedtls. + * @author MicroEJ Developer Team + * @version 2.1.6 + * @date 17 January 2023 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include "mbedtls/debug.h" +#include "LLNET_SSL_CONTEXT_impl.h" +#include "LLNET_SSL_CONSTANTS.h" +#include "LLNET_SSL_ERRORS.h" +#include "LLNET_SSL_utils_mbedtls.h" +#include "LLNET_SSL_verifyCallback.h" +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#if MBEDTLS_DEBUG_LEVEL > 0 +#define CERT_INFO_BUF_SIZE 1024 + +/* + * If mbedtls debug level activated, print full informations on certificates + */ +static char cert_info_buf_debug[CERT_INFO_BUF_SIZE] = {0}; + +#endif + +/** + * Certificate verification callback for mbed TLS + * Here we only use it to display information on each cert in the chain + */ +int LLNET_SSL_VERIFY_verifyCallback(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) +{ +#if MBEDTLS_DEBUG_LEVEL > 0 + printf("\nVerifying certificate at depth %d:\n", depth); + mbedtls_x509_crt_info(&cert_info_buf_debug[0], CERT_INFO_BUF_SIZE - 1, " ", crt); //-1 to keep last byte for null-terminated character + printf("%s", &cert_info_buf_debug[0]); + + if (0 == *flags) + printf("No verification issue for this certificate\n"); + else + { + mbedtls_x509_crt_verify_info(&cert_info_buf_debug[0], CERT_INFO_BUF_SIZE, " ! ", *flags); + printf("%s\n", &cert_info_buf_debug[0]); + } +#endif + + cert_verify_ctx* verify_ctx = (cert_verify_ctx*)data; + + /* If no certificate from peer is signed by on of the trust certificate, + * check if one of the trust certificate is identical to one of the peer certificate */ + if (MBEDTLS_X509_BADCERT_NOT_TRUSTED == ((*flags) & MBEDTLS_X509_BADCERT_NOT_TRUSTED)) + { + LLNET_SSL_DEBUG_TRACE("%s(depth=%d) Certificate not trusted, clear error flag and lookup for identical certificate\n", __func__,depth); + + verify_ctx->isUnTrustCA = 1; + + /* Clear error flag*/ + *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED; + } + + if (0 != verify_ctx->isUnTrustCA) + { + /* Compare peer certificate with trusted certificates */ + + mbedtls_x509_crt* trust_ca = NULL; + + /* Look for certificate in trust store that match peer certificate */ + for( trust_ca = verify_ctx->conf->ca_chain; trust_ca != NULL; trust_ca = trust_ca->next ) + { + uint8_t raw_compare = -1; + + /* compare certificate raw content */ + if (trust_ca->raw.len == crt->raw.len) + { + raw_compare = memcmp(trust_ca->raw.p, crt->raw.p, trust_ca->raw.len); + } + + if (0 == raw_compare) + { + LLNET_SSL_DEBUG_TRACE("%s(depth=%d) Found identical certificate in trust store\n", __func__, depth); + verify_ctx->isUnTrustCA = 0; + } + else + continue; + + break; + + } + } + + /* if this is the last certificate of the peer chain, set back error flag */ + if ( (0 == depth) && (0 != verify_ctx->isUnTrustCA)) + { + LLNET_SSL_DEBUG_TRACE("%s(depth=%d) No trusted nor identical certificate in trust store\n", __func__, depth); + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + /* Reset isUnTrustCA flag in verify context */ + verify_ctx->isUnTrustCA = 0; + } + + return 0; +} + +#ifdef __cplusplus + } +#endif diff --git a/bsp/projects/microej/ui/inc/display_configuration.h b/bsp/projects/microej/ui/inc/display_configuration.h new file mode 100644 index 0000000..a87c970 --- /dev/null +++ b/bsp/projects/microej/ui/inc/display_configuration.h @@ -0,0 +1,17 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef DISPLAY_CONFIGURATION_H +#define DISPLAY_CONFIGURATION_H + +/* structure that contains the region to update, unit: px */ +typedef struct { + int32_t x_offset; + int32_t y_offset; + uint32_t width; + uint32_t height; +} DISPLAY_CONFIGURATION_flush_region; + +#endif diff --git a/bsp/projects/microej/ui/inc/event_generator.h b/bsp/projects/microej/ui/inc/event_generator.h new file mode 100644 index 0000000..e119e08 --- /dev/null +++ b/bsp/projects/microej/ui/inc/event_generator.h @@ -0,0 +1,112 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +/* + * This header files groups several APIs to notify to a or several events handlers an + * event has occured on an input driver (buttons, touch etc.). + * + * The idea is to disconnect the management of the inputs drivers (how to initialize an + * input driver, how to get/read an input event, how to clear it, etc.) and how to + * send these inputs events to the MicroUI application using the MicroUI EventGenerators. + * + * The MicroUI framework is using an internal buffer to store the inputs events. The event + * will not be added if the internal events buffer is full. In this case the input driver + * has to adapt itself in order to not send a future invalid event. For instance, if a + * PRESSED event is not sent, the input driver has not to send a REPEAT or RELEASE event. + * So it may have a distinction between the real input state and the "software" input + * state. + */ +#ifndef _EVENT_GENERATOR +#define _EVENT_GENERATOR + +/* Includes ------------------------------------------------------------------*/ + +#include + +/* API -----------------------------------------------------------------------*/ + +/* + * Notify to the event generator a button has been pressed. + * @param buttonId the button ID, between 0 and 255 + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_button_pressed(int32_t buttonId); + +/* + * Notify to the event generator a button has been repeated. + * @param buttonId the button ID, between 0 and 255 + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_button_repeated(int32_t buttonId); + +/* + * Notify to the event generator a button has been released. + * @param buttonId the button ID, between 0 and 255 + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_button_released(int32_t buttonId); + +/* + * Notify to the event generator a pointer button has been pressed. + * @param buttonId the button ID, between 0 and 255 + * @param x the pointer X coordinate + * @param y the pointer Y coordinate + * @param type {@link LLUI_INPUT_ABSOLUTE} when (x,y) coordinates are absolute, {@link LLUI_INPUT_RELATIVE} when + * there are relative to the previous pointer position + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_pointer_pressed(int32_t buttonID, int32_t x, int32_t y, int32_t type); + +/* + * Notify to the event generator a pointer has moved. + * @param x the pointer X coordinate + * @param y the pointer Y coordinate + * @param absolute {@link LLUI_INPUT_ABSOLUTE} when (x,y) coordinates are absolute, {@link LLUI_INPUT_RELATIVE} when + * there are relative to the previous pointer position + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_pointer_moved(int32_t x, int32_t y, int32_t type); + +/* + * Notify to the event generator a pointer button has been released. + * @param buttonId the button ID, between 0 and 255 + * @return {@link LLUI_INPUT_OK} if the event has been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_pointer_released(int32_t buttonID); + +/* + * Notify to the event generator a touch has been pressed. + * @param x the pointer X coordinate + * @param y the pointer Y coordinate + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_touch_pressed(int32_t x, int32_t y); + +/* + * Notify to the event generator a touch has moved. + * @param x the pointer X coordinate + * @param y the pointer Y coordinate + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_touch_moved(int32_t x, int32_t y); + +/* + * Notify to the event generator a touch has been released. + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_touch_released(void); + +/* + * Notify to the event generator a state has changed. + * @param stateID the state machine identifier, between 0 and 255 + * @param stateValue the new state if the state machine, between 0 and 255 + * @return {@link LLUI_INPUT_OK} if all events have been added, {@link LLUI_INPUT_NOK} otherwise + */ +int32_t EVENT_GENERATOR_state_changed(int32_t stateID, int32_t stateValue); + +#endif diff --git a/bsp/projects/microej/ui/inc/framerate.h b/bsp/projects/microej/ui/inc/framerate.h new file mode 100644 index 0000000..5e2a1e0 --- /dev/null +++ b/bsp/projects/microej/ui/inc/framerate.h @@ -0,0 +1,50 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ +#ifndef _FRAMERATE_INTERN +#define _FRAMERATE_INTERN + +/* Includes ------------------------------------------------------------------*/ + +#include +#include "framerate_conf.h" + +/* Defines -------------------------------------------------------------------*/ + +#define FRAMERATE_OK 0 +#define FRAMERATE_ERROR -1 + +#ifndef FRAMERATE_SCHEDULE_TIME +#define FRAMERATE_SCHEDULE_TIME 500 // ms +#endif + +/* API -----------------------------------------------------------------------*/ + +/* + * Initialize the framework + */ +int32_t framerate_init(int32_t schedule_time); + +/* + * Update the framerate counter + */ +void framerate_increment(void); + +/* + * Return the last framerate + */ +uint32_t framerate_get(void); + +/* Default Java API ----------------------------------------------------------*/ + +#ifndef javaFramerateInit +#define javaFramerateInit Java_com_is2t_debug_Framerate_init +#endif +#ifndef javaFramerateGet +#define javaFramerateGet Java_com_is2t_debug_Framerate_get +#endif + +#endif // _FRAMERATE_INTERN diff --git a/bsp/projects/microej/ui/inc/framerate_conf.h b/bsp/projects/microej/ui/inc/framerate_conf.h new file mode 100644 index 0000000..9326332 --- /dev/null +++ b/bsp/projects/microej/ui/inc/framerate_conf.h @@ -0,0 +1,18 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ +#ifndef _FRAMERATE_CONF +#define _FRAMERATE_CONF + +/* Defines -------------------------------------------------------------------*/ + +/* + * Comment / uncomment it to enable / disable the framerate + */ +#define FRAMERATE_ENABLED +//#define FRAMERATE_INIT_C + +#endif diff --git a/bsp/projects/microej/ui/inc/framerate_impl.h b/bsp/projects/microej/ui/inc/framerate_impl.h new file mode 100644 index 0000000..6b1dc46 --- /dev/null +++ b/bsp/projects/microej/ui/inc/framerate_impl.h @@ -0,0 +1,40 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * Implement the *_impl* functions according the CPU/OS/Compiler + */ + +#ifndef _FRAMERATE_IMPL +#define _FRAMERATE_IMPL + +/* Includes ------------------------------------------------------------------*/ + +#include "framerate.h" + +/* API -----------------------------------------------------------------------*/ + +#ifdef FRAMERATE_ENABLED + +/* + * Framerate task have just to call this function + */ +void framerate_task_work(void); + +/* + * Create and start a framerate task + */ +int32_t framerate_impl_start_task(void); + +/* + * Sleep the framerate task + */ +void framerate_impl_sleep(uint32_t ms); + +#endif // FRAMERATE_ENABLED + +#endif // _FRAMERATE_IMPL diff --git a/bsp/projects/microej/ui/inc/interrupts.h b/bsp/projects/microej/ui/inc/interrupts.h new file mode 100644 index 0000000..460f415 --- /dev/null +++ b/bsp/projects/microej/ui/inc/interrupts.h @@ -0,0 +1,23 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +#ifndef _INTERRUPTS +#define _INTERRUPTS + +/* Includes ------------------------------------------------------------------*/ + +#include "microej.h" + +/* API -----------------------------------------------------------------------*/ + +/** + * This function returns MICROEJ_TRUE or MICROEJ_FALSE to indicate if an ISR is currently executed. + */ +uint8_t interrupt_is_in(void); + +#endif diff --git a/bsp/projects/microej/ui/inc/lcd.h b/bsp/projects/microej/ui/inc/lcd.h new file mode 100644 index 0000000..5f93970 --- /dev/null +++ b/bsp/projects/microej/ui/inc/lcd.h @@ -0,0 +1,55 @@ +/** + * Copyright 2021-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#if !defined __DISPLAY_TRANSFER_H__ +#define __DISPLAY_TRANSFER_H__ + +#include "panel_func.h" + +// ---------------------------------------------------------------------------- +// Preprocessor Directives +// ---------------------------------------------------------------------------- + +/* Display orientation */ +#define PORTRAIT 1 +#define LANDSCAPE 2 +#define PORTRAIT_FLIP 3 +#define LANDSCAPE_FLIP 4 + + +#define SWAP_FN(c) ((((c) & 0xff00)>>8) | (((c) & 0xff) << 8)) + +/* + * #brief Sets the default orientation mode + * + * Set this preprocessing directive to: + * - LANDSCAPE to use the landscape mode + * - PORTRAIT to use the portrait mode + */ +#define DEFAULT_ORIENTATION_MODE LANDSCAPE +//#define DEFAULT_ORIENTATION_MODE PORTRAIT + +/* + * @brief Horizontal and Vertical resolution + */ +#if DEFAULT_ORIENTATION_MODE == LANDSCAPE +#define DISPLAY_PHYSICAL_HREZ APP_LCD_WIDTH +#define DISPLAY_PHYSICAL_VREZ APP_LCD_HEIGHT +#else +#define DISPLAY_PHYSICAL_HREZ APP_LCD_HEIGHT +#define DISPLAY_PHYSICAL_VREZ APP_LCD_WIDTH +#endif + +#define DISPLAY_HREZ DISPLAY_PHYSICAL_HREZ +#define DISPLAY_VREZ DISPLAY_PHYSICAL_VREZ + +/* Define size to allocate for Display buffer. (320 * 240 * 2) x 1 : 1 for BACK_BUFFER */ +#define LLUI_DISPLAY_BPP 16 + +#define FRAME_BUFFER_HEIGHT DISPLAY_VREZ + +#define FRAME_BUFFER_SIZE ((DISPLAY_HREZ * FRAME_BUFFER_HEIGHT * LLUI_DISPLAY_BPP) / 8) + +#endif // !defined __DISPLAY_TRANSFER_H__ diff --git a/bsp/projects/microej/ui/inc/lcdic_panel_config.h b/bsp/projects/microej/ui/inc/lcdic_panel_config.h new file mode 100644 index 0000000..739e889 --- /dev/null +++ b/bsp/projects/microej/ui/inc/lcdic_panel_config.h @@ -0,0 +1,25 @@ +/* + * Copyright 2022 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _LCDIC_PANEL_CONFIG_H_ +#define _LCDIC_PANEL_CONFIG_H_ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Define 1 to use it */ +#define APP_PANEL_ADAFRUIT_2_8_CAPTATIVE 1 + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _LCDIC_PANEL_CONFIG_H_ */ diff --git a/bsp/projects/microej/ui/inc/microej.h b/bsp/projects/microej/ui/inc/microej.h new file mode 100644 index 0000000..70de25b --- /dev/null +++ b/bsp/projects/microej/ui/inc/microej.h @@ -0,0 +1,21 @@ +/* + * C + * + * Copyright 2013-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +#ifndef __MICROEJ_H +#define __MICROEJ_H + +/* Includes ------------------------------------------------------------------*/ + +#include + +/* Defines -------------------------------------------------------------------*/ + +#define MICROEJ_FALSE ((uint8_t) 0) +#define MICROEJ_TRUE ((uint8_t) 1) + +#endif diff --git a/bsp/projects/microej/ui/inc/microui_event_decoder.h b/bsp/projects/microej/ui/inc/microui_event_decoder.h new file mode 100644 index 0000000..6bd997c --- /dev/null +++ b/bsp/projects/microej/ui/inc/microui_event_decoder.h @@ -0,0 +1,102 @@ +/* + * C + * + * Copyright 2021-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * @file + * @brief See microui_event_decoder.c. + * @author MicroEJ Developer Team + * @version 2.0.1 + * @date 16 December 2022 + * @since MicroEJ UI Pack 13.1.0 + */ + +#if !defined MICROUI_EVENT_DECODER_H +# define MICROUI_EVENT_DECODER_H + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include +#include +#include + +#include "microui_event_decoder_conf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MICROUIEVENTDECODER_ENABLED + +// ----------------------------------------------------------------------------- +// Types +// ----------------------------------------------------------------------------- + +/* + * @brief Function to decode the data of an event. + * + * @param[in] event the event that requires the data. + * @param[in] data the event data. + * @param[in] index the data index in queue. + */ +typedef void (* MICROUI_EVENT_DECODER_decode_event_data) (uint32_t event, uint32_t data, uint32_t index); + +// ----------------------------------------------------------------------------- +// API +// ----------------------------------------------------------------------------- + +/* + * @brief Notifies the start of MicroUI FIFO dump. + */ +void MICROUI_EVENT_DECODER_describe_dump_start(void); + +/* + * @brief Notifies the next logs are already consumed. + */ +void MICROUI_EVENT_DECODER_describe_dump_past(void); + +/* + * @brief Notifies the next logs are not consumed yet. + */ +void MICROUI_EVENT_DECODER_describe_dump_future(void); + +/* + * @brief Notifies the dump will log the Java objects associated with the events + * that are not consumed yet. + */ +void MICROUI_EVENT_DECODER_describe_dump_events_objects(void); + +/* + * @brief Notifies the end of MicroUI FIFO dump. + */ +void MICROUI_EVENT_DECODER_describe_dump_end(void); + +/* + * @brief Drops a data. This is an orphaned data of an old event already executed. + */ +void MICROUI_EVENT_DECODER_drop_data(uint32_t data, uint32_t index); + +/* + * @brief Decodes an event. + * + * @param[in] event the 32-bit event. + * @param[in] index the event's index in queue. + * @param[out] fct_data_decoder function to decode the data of the event. + */ +void MICROUI_EVENT_DECODER_decode_event(uint32_t event, uint32_t index, MICROUI_EVENT_DECODER_decode_event_data* fct_data_decoder); + +#endif // MICROUIEVENTDECODER_ENABLED + +// ----------------------------------------------------------------------------- +// EOF +// ----------------------------------------------------------------------------- + +#ifdef __cplusplus +} +#endif +#endif // MICROUI_EVENT_DECODER_H diff --git a/bsp/projects/microej/ui/inc/microui_event_decoder_conf.h b/bsp/projects/microej/ui/inc/microui_event_decoder_conf.h new file mode 100644 index 0000000..d7cf3cf --- /dev/null +++ b/bsp/projects/microej/ui/inc/microui_event_decoder_conf.h @@ -0,0 +1,103 @@ +/* + * C + * + * Copyright 2021-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + * + * Copyright 2024 NXP + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file + * @brief This file allows to configure the implementation of microui_event_decoder.c. + * @author MicroEJ Developer Team + * @version 2.0.1 + * @date 16 December 2022 + * @since MicroEJ UI Pack 13.1.0 + */ + +#if !defined MICROUI_EVENT_DECODER_CONF_H +# define MICROUI_EVENT_DECODER_CONF_H + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include "fsl_debug_console.h" + +// header file created by MicroEJ Platform builder. +#include "microui_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ----------------------------------------------------------------------------- +// Defines +// ----------------------------------------------------------------------------- + +/* + * @brief When defined, the logger is enabled. The call to LLUI_INPUT_dump() + * has no effect when the logger is disabled. + * + * By default the logger is not enabled. + */ +#define MICROUIEVENTDECODER_ENABLED + +#ifdef MICROUIEVENTDECODER_ENABLED + +/* + * @brief When defined, the MicroUI event decoder is able to decode the *input* + * "Command" events. The define's value is the MicroUI Event Generator + * "Command" fixed in the microui.xml file and used to build the MicroEJ Platform. + * Most of time the MicroUI Event Generator "Command" is "MICROUI_EVENTGEN_COMMANDS": + * + * #define MICROUIEVENTDECODER_EVENTGEN_COMMAND MICROUI_EVENTGEN_COMMANDS + * + * When not defined, the MicroUI event decoder does not try to decode the MicroUI + * events "Command". + */ +//#define MICROUIEVENTDECODER_EVENTGEN_COMMAND MICROUI_EVENTGEN_COMMANDS + +/* + * @brief When defined, the MicroUI event decoder is able to decode the *input* + * "Buttons" events. The define's value is the MicroUI Event Generator + * "Buttons" fixed in the microui.xml file and used to build the MicroEJ Platform. + * Most of time the MicroUI Event Generator "Buttons" is "MICROUI_EVENTGEN_BUTTONS": + * + * #define MICROUIEVENTDECODER_EVENTGEN_BUTTONS MICROUI_EVENTGEN_BUTTONS + * + * When not defined, the MicroUI event decoder does not try to decode the MicroUI + * events "Buttons". + */ +//#define MICROUIEVENTDECODER_EVENTGEN_BUTTONS MICROUI_EVENTGEN_BUTTONS + +/* + * @brief When defined, the MicroUI event decoder is able to decode the *input* + * "Touch" events. The define's value is the MicroUI Event Generator + * "Touch" fixed in the microui.xml file and used to build the MicroEJ Platform. + * Most of time the MicroUI Event Generator "Touch" is "MICROUI_EVENTGEN_TOUCH": + * + * #define MICROUIEVENTDECODER_EVENTGEN_TOUCH MICROUI_EVENTGEN_TOUCH + * + * When not defined, the MicroUI event decoder does not try to decode the MicroUI + * events "Touch". + */ +#define MICROUIEVENTDECODER_EVENTGEN_TOUCH MICROUI_EVENTGEN_TOUCH + +/* + * Standard "printf" indirection. + */ +#define LLUI_DEBUG_TRACE (void)PRINTF + +#endif // MICROUIEVENTDECODER_ENABLED + +// ----------------------------------------------------------------------------- +// EOF +// ----------------------------------------------------------------------------- + +#ifdef __cplusplus +} +#endif +#endif // MICROUI_EVENT_DECODER_CONF_H diff --git a/bsp/projects/microej/ui/inc/microui_heap.h b/bsp/projects/microej/ui/inc/microui_heap.h new file mode 100644 index 0000000..12ee49d --- /dev/null +++ b/bsp/projects/microej/ui/inc/microui_heap.h @@ -0,0 +1,68 @@ +/* + * C + * + * Copyright 2021-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * @file + * @brief See LLUI_DISPLAY_HEAP_impl.c. + * @author MicroEJ Developer Team + * @version 2.0.1 + * @date 16 December 2022 + * @since MicroEJ UI Pack 13.1.0 + */ + +#if !defined MICROUI_HEAP_H +# define MICROUI_HEAP_H + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// ----------------------------------------------------------------------------- +// API +// ----------------------------------------------------------------------------- + +/* + * @brief Returns the MicroUI image heap size in bytes. + */ +uint32_t MICROUI_HEAP_total_space(void); + +/* + * @brief Returns the MicroUI image heap free space size in bytes. + * + * Warnings: The total free space cannot contain a block whose size is equal to + * the total free space: + * - The best fit allocator adds a header and a footer for each allocated + * block. + * - Consecutive malloc/free produce cause memory fragmentation (all the free + * blocks are not contiguous in the memory). The function returns the sum of + * all the free blocks. + */ +uint32_t MICROUI_HEAP_free_space(void); + +/* + * @brief Returns the number of blocks allocated. + * + * The MicroUI image heap is mainly used to allocate the pixels buffers of MicroUI + * ResourceImages (images decoded dynamically at runtime, copy of images located in + * a non-byte addressable memory, and MicroUI BufferedImages). + */ +uint32_t MICROUI_HEAP_number_of_allocated_blocks(void); + +// ----------------------------------------------------------------------------- +// EOF +// ----------------------------------------------------------------------------- + +#ifdef __cplusplus +} +#endif +#endif // MICROUI_HEAP_H diff --git a/bsp/projects/microej/ui/inc/panel_func.h b/bsp/projects/microej/ui/inc/panel_func.h new file mode 100644 index 0000000..db45426 --- /dev/null +++ b/bsp/projects/microej/ui/inc/panel_func.h @@ -0,0 +1,58 @@ +/* + * Copyright 2022 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2023 MicroEJ Corp. This file has been modified by MicroEJ Corp. + * Use of this source code is governed by a BSD-style license that can be found with this software. + * + */ + +#ifndef _PANEL_FUNC_H_ +#define _PANEL_FUNC_H_ + +#include +#include "lcdic_panel_config.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define APP_LCD_BIG_ENDIAN 0 +#define APP_LCD_LITTLE_ENDIAN 1 + +#if (defined(APP_PANEL_ADAFRUIT_2_8_CAPTATIVE) && APP_PANEL_ADAFRUIT_2_8_CAPTATIVE) +#define APP_LCD_HEIGHT 240u +#define APP_LCD_WIDTH 320u + + +#ifdef I8080_SCREEN + #define APP_LCDIC_MODE kLCDIC_I8080 + #define APP_LCDIC_8080_FLAG \ + ((uint8_t)kLCDIC_I8080_CsActiveLow | (uint8_t)kLCDIC_I8080_DcCmdLow | \ + (uint8_t)kLCDIC_I8080_RdActiveLow | (uint8_t)kLCDIC_I8080_WrActiveLow | \ + (uint8_t)kLCDIC_I8080_CsEnableIdleOff) +#else + #define APP_LCDIC_MODE kLCDIC_4WireSPI + #define APP_LCDIC_SPI_FLAG \ + (kLCDIC_SPI_MsbFirst | kLCDIC_SPI_ClkActiveLow | kLCDIC_SPI_ClkPhaseSecondEdge | kLCDIC_SPI_DcCmdLow) + +#endif + +#define APP_LCDI_ENDIAN APP_LCD_BIG_ENDIAN + +#endif + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +void APP_InitPanel(void); + +void APP_PanelSelectRegion(uint16_t startX, uint16_t startY, uint16_t endX, uint16_t endY); + +void APP_InitFlexioMcuLcd(void); +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _PANEL_FUNC_H_ */ diff --git a/bsp/projects/microej/ui/inc/touch_helper.h b/bsp/projects/microej/ui/inc/touch_helper.h new file mode 100644 index 0000000..c47cdb0 --- /dev/null +++ b/bsp/projects/microej/ui/inc/touch_helper.h @@ -0,0 +1,37 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +#ifndef _TOUCH_HELPER +#define _TOUCH_HELPER + +/* Includes ------------------------------------------------------------------*/ + +#include + +/* API -----------------------------------------------------------------------*/ + +/* + * Notify to an event handler a touch has been pressed. + * @param x the pointer X coordinate + * @param y the pointer Y coordinate + */ +void TOUCH_HELPER_pressed(int32_t x, int32_t y); + +/* + * Notify to an event handler a touch has moved. + * @param x the pointer X coordinate + * @param y the pointer Y coordinate + */ +void TOUCH_HELPER_moved(int32_t x, int32_t y); + +/* + * Notify to an event handler a touch has been released. + */ +void TOUCH_HELPER_released(void); + +#endif diff --git a/bsp/projects/microej/ui/inc/touch_helper_configuration.h b/bsp/projects/microej/ui/inc/touch_helper_configuration.h new file mode 100644 index 0000000..564395b --- /dev/null +++ b/bsp/projects/microej/ui/inc/touch_helper_configuration.h @@ -0,0 +1,20 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +#ifndef _TOUCH_HELPER_CONFIGURATION +#define _TOUCH_HELPER_CONFIGURATION + +/* Defines -------------------------------------------------------------------*/ + +// Number of pixels to generate a move after a press +#define FIRST_MOVE_PIXEL_LIMIT 8 + +// Number of pixels to generate a move after a move +#define MOVE_PIXEL_LIMIT 2 + +#endif diff --git a/bsp/projects/microej/ui/inc/touch_manager.h b/bsp/projects/microej/ui/inc/touch_manager.h new file mode 100644 index 0000000..bf166ba --- /dev/null +++ b/bsp/projects/microej/ui/inc/touch_manager.h @@ -0,0 +1,27 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +#ifndef _TOUCH_MANAGER +#define _TOUCH_MANAGER + +/* Includes ------------------------------------------------------------------*/ + +#include + +#define TOUCH_INTERRUPT_PORT 0U +#define TOUCH_INTERRUPT_PIN 10U +#define APP_GPIO_INTA_IRQHandler GPIO_INTA_DriverIRQHandler +#define TOUCH_INTERRUPT_IRQ GPIO_INTA_IRQn +#define TOUCH_INTERRUPT_CONNECTED_LEVEL 0U + +/* API -----------------------------------------------------------------------*/ + +void TOUCH_MANAGER_initialize(void); +void TOUCH_MANAGER_interrupt(void); + +#endif diff --git a/bsp/projects/microej/ui/microej_ui.cmake b/bsp/projects/microej/ui/microej_ui.cmake new file mode 100644 index 0000000..5f3255e --- /dev/null +++ b/bsp/projects/microej/ui/microej_ui.cmake @@ -0,0 +1,21 @@ +# Copyright 2022-2023 MicroEJ Corp. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be found with this software. + +include_guard() +message("microej/ui component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/LLDW_PAINTER_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLUI_DISPLAY_HEAP_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLUI_PAINTER_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/microui_event_decoder.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLUI_INPUT_LOG_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLUI_INPUT.c + ${CMAKE_CURRENT_LIST_DIR}/src/LLUI_DISPLAY.c + ${CMAKE_CURRENT_LIST_DIR}/src/interrupts.c + ${CMAKE_CURRENT_LIST_DIR}/src/touch_helper.c + ${CMAKE_CURRENT_LIST_DIR}/src/event_generator.c + ${CMAKE_CURRENT_LIST_DIR}/src/touch_manager.c +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) diff --git a/bsp/projects/microej/ui/src/LLDW_PAINTER_impl.c b/bsp/projects/microej/ui/src/LLDW_PAINTER_impl.c new file mode 100644 index 0000000..d68c79e --- /dev/null +++ b/bsp/projects/microej/ui/src/LLDW_PAINTER_impl.c @@ -0,0 +1,183 @@ + +/* + * Copyright 2020-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * @file + * @brief This file implements all "Drawing" (MicroUI extended library) drawing native functions. + * @see LLDW_PAINTER_impl.h file comment + * @author MicroEJ Developer Team + * @version 2.0.1 + * @date 16 December 2022 + * @since MicroEJ UI Pack 13.0.0 + */ + +// -------------------------------------------------------------------------------- +// Includes +// -------------------------------------------------------------------------------- + +// implements LLDW_PAINTER_impl functions +#include "LLDW_PAINTER_impl.h" + +// calls dw_drawing functions +#include "dw_drawing.h" + +// use graphical engine functions to synchronize drawings +#include "LLUI_DISPLAY.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// -------------------------------------------------------------------------------- +// Macros and Defines +// -------------------------------------------------------------------------------- + +// macros to log a drawing +#define LOG_DRAW_START(fn) LLUI_DISPLAY_logDrawingStart(CONCAT_DEFINES(LOG_DRAW_, fn)) +#define LOG_DRAW_END(fn) LLUI_DISPLAY_logDrawingEnd(CONCAT_DEFINES(LOG_DRAW_, fn)) + +/* + * LOG_DRAW_EVENT logs identifiers + */ +#define LOG_DRAW_drawThickFadedPoint 100 +#define LOG_DRAW_drawThickFadedLine 101 +#define LOG_DRAW_drawThickFadedCircle 102 +#define LOG_DRAW_drawThickFadedCircleArc 103 +#define LOG_DRAW_drawThickFadedEllipse 104 +#define LOG_DRAW_drawThickLine 105 +#define LOG_DRAW_drawThickCircle 106 +#define LOG_DRAW_drawThickEllipse 107 +#define LOG_DRAW_drawThickCircleArc 108 + +#define LOG_DRAW_drawFlippedImage 200 +#define LOG_DRAW_drawRotatedImageNearestNeighbor 201 +#define LOG_DRAW_drawRotatedImageBilinear 202 +#define LOG_DRAW_drawScaledImageNearestNeighbor 203 +#define LOG_DRAW_drawScaledImageBilinear 204 + +// -------------------------------------------------------------------------------- +// LLDW_PAINTER_impl.h functions +// -------------------------------------------------------------------------------- + +void LLDW_PAINTER_IMPL_drawThickFadedPoint(MICROUI_GraphicsContext* gc, jint x, jint y, jint thickness, jint fade) { + if (((thickness > 0) || (fade > 0)) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickFadedPoint)) { + LOG_DRAW_START(drawThickFadedPoint); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickFadedPoint(gc, x, y, thickness, fade)); + LOG_DRAW_END(drawThickFadedPoint); + } +} + +void LLDW_PAINTER_IMPL_drawThickFadedLine(MICROUI_GraphicsContext* gc, jint startX, jint startY, jint endX, jint endY, jint thickness, jint fade, DRAWING_Cap startCap, DRAWING_Cap endCap) { + if (((thickness > 0) || (fade > 0)) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickFadedLine)) { + LOG_DRAW_START(drawThickFadedLine); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickFadedLine(gc, startX, startY, endX, endY, thickness, fade, startCap, endCap)); + LOG_DRAW_END(drawThickFadedLine); + } +} + +void LLDW_PAINTER_IMPL_drawThickFadedCircle(MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter, jint thickness, jint fade) { + if (((thickness > 0) || (fade > 0)) && (diameter > 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickFadedCircle)) { + LOG_DRAW_START(drawThickFadedCircle); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickFadedCircle(gc, x, y, diameter, thickness, fade)); + LOG_DRAW_END(drawThickFadedCircle); + } +} + +void LLDW_PAINTER_IMPL_drawThickFadedCircleArc(MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter, jfloat startAngle, jfloat arcAngle, jint thickness, jint fade, DRAWING_Cap start, DRAWING_Cap end) { + if (((thickness > 0) || (fade > 0)) && (diameter > 0) && ((int32_t)arcAngle != 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickFadedCircleArc)) { + LOG_DRAW_START(drawThickFadedCircleArc); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickFadedCircleArc(gc, x, y, diameter, startAngle, arcAngle, thickness, fade, start, end)); + LOG_DRAW_END(drawThickFadedCircleArc); + } +} + +void LLDW_PAINTER_IMPL_drawThickFadedEllipse(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jint thickness, jint fade) { + if (((thickness > 0) || (fade > 0)) && (width > 0) && (height > 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickFadedEllipse)) { + LOG_DRAW_START(drawThickFadedEllipse); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickFadedEllipse(gc, x, y, width, height, thickness, fade)); + LOG_DRAW_END(drawThickFadedEllipse); + } +} + +void LLDW_PAINTER_IMPL_drawThickLine(MICROUI_GraphicsContext* gc, jint startX, jint startY, jint endX, jint endY, jint thickness) { + if ((thickness > 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickLine)) { + LOG_DRAW_START(drawThickLine); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickLine(gc, startX, startY, endX, endY, thickness)); + LOG_DRAW_END(drawThickLine); + } +} + +void LLDW_PAINTER_IMPL_drawThickCircle(MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter, jint thickness) { + if ((thickness > 0) && (diameter > 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickCircle)) { + LOG_DRAW_START(drawThickCircle); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickCircle(gc, x, y, diameter, thickness)); + LOG_DRAW_END(drawThickCircle); + } +} + +void LLDW_PAINTER_IMPL_drawThickEllipse(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jint thickness) { + if ((thickness > 0) && (width > 0) && (height > 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickEllipse)) { + LOG_DRAW_START(drawThickEllipse); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickEllipse(gc, x, y, width, height, thickness)); + LOG_DRAW_END(drawThickEllipse); + } +} + +void LLDW_PAINTER_IMPL_drawThickCircleArc(MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter, jfloat startAngle, jfloat arcAngle, jint thickness) { + if ((thickness > 0) && (diameter > 0) && ((int32_t)arcAngle != 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawThickCircleArc)) { + LOG_DRAW_START(drawThickCircleArc); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawThickCircleArc(gc, x, y, diameter, startAngle, arcAngle, thickness)); + LOG_DRAW_END(drawThickCircleArc); + } +} + +void LLDW_PAINTER_IMPL_drawFlippedImage(MICROUI_GraphicsContext* gc, MICROUI_Image* img, jint regionX, jint regionY, jint width, jint height, jint x, jint y, DRAWING_Flip transformation, jint alpha) { + if (!LLUI_DISPLAY_isClosed(img) && (alpha > 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawFlippedImage)) { + LOG_DRAW_START(drawFlippedImage); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawFlippedImage(gc, img, regionX, regionY, width, height, x, y, transformation, alpha)); + LOG_DRAW_END(drawFlippedImage); + } +} + +void LLDW_PAINTER_IMPL_drawRotatedImageNearestNeighbor(MICROUI_GraphicsContext* gc, MICROUI_Image* img, jint x, jint y, jint rotationX, jint rotationY, jfloat angle, jint alpha) { + if (!LLUI_DISPLAY_isClosed(img) && (alpha > 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawRotatedImageNearestNeighbor)) { + LOG_DRAW_START(drawRotatedImageNearestNeighbor); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawRotatedImageNearestNeighbor(gc, img, x, y, rotationX, rotationY, angle, alpha)); + LOG_DRAW_END(drawRotatedImageNearestNeighbor); + } +} + +void LLDW_PAINTER_IMPL_drawRotatedImageBilinear(MICROUI_GraphicsContext* gc, MICROUI_Image* img, jint x, jint y, jint rotationX, jint rotationY, jfloat angle, jint alpha) { + if (!LLUI_DISPLAY_isClosed(img) && (alpha > 0) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawRotatedImageBilinear)) { + LOG_DRAW_START(drawRotatedImageBilinear); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawRotatedImageBilinear(gc, img, x, y, rotationX, rotationY, angle, alpha)); + LOG_DRAW_END(drawRotatedImageBilinear); + } +} + +void LLDW_PAINTER_IMPL_drawScaledImageNearestNeighbor(MICROUI_GraphicsContext* gc, MICROUI_Image* img, jint x, jint y, jfloat factorX, jfloat factorY, jint alpha) { + if (!LLUI_DISPLAY_isClosed(img) && (alpha > 0) && (factorX > 0.f) && (factorY > 0.f) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawScaledImageNearestNeighbor)) { + LOG_DRAW_START(drawScaledImageNearestNeighbor); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawScaledImageNearestNeighbor(gc, img, x, y, factorX, factorY, alpha)); + LOG_DRAW_END(drawScaledImageNearestNeighbor); + } +} + +void LLDW_PAINTER_IMPL_drawScaledImageBilinear(MICROUI_GraphicsContext* gc, MICROUI_Image* img, jint x, jint y, jfloat factorX, jfloat factorY, jint alpha) { + if (!LLUI_DISPLAY_isClosed(img) && (alpha > 0) && (factorX > 0.f) && (factorY > 0.f) && LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLDW_PAINTER_IMPL_drawScaledImageBilinear)) { + LOG_DRAW_START(drawScaledImageBilinear); + LLUI_DISPLAY_setDrawingStatus(DW_DRAWING_drawScaledImageBilinear(gc, img, x, y, factorX, factorY, alpha)); + LOG_DRAW_END(drawScaledImageBilinear); + } +} + +// -------------------------------------------------------------------------------- +// EOF +// -------------------------------------------------------------------------------- + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/ui/src/LLUI_DISPLAY.c b/bsp/projects/microej/ui/src/LLUI_DISPLAY.c new file mode 100644 index 0000000..186c795 --- /dev/null +++ b/bsp/projects/microej/ui/src/LLUI_DISPLAY.c @@ -0,0 +1,116 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include +#include "lcdic_panel_config.h" +#include "LLUI_DISPLAY_impl.h" +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +#include "sni.h" +#include "lcd.h" + + +#include "fsl_common.h" +#include "pin_mux.h" +#include "fsl_debug_console.h" +#include "display_configuration.h" +#include "display_support.h" + +/****************************UI PORT FUNCTION***************************************/ + +void LLUI_DISPLAY_IMPL_initialize(LLUI_DISPLAY_SInitData* init_data) +{ + // Initialize context data. + init_data->back_buffer_address = disp_sup_get_fb_address(); + init_data->lcd_height = LCD_HEIGHT; + init_data->lcd_width = LCD_WIDTH; + + init_data->binary_semaphore_0 = (LLUI_DISPLAY_binary_semaphore*) xSemaphoreCreateBinary(); + init_data->binary_semaphore_1 = (LLUI_DISPLAY_binary_semaphore*) xSemaphoreCreateBinary(); + + disp_sup_pre_init(); + disp_sup_disp_init(); + disp_sup_indev_init(); +} + +static DISPLAY_CONFIGURATION_flush_region flush_region; + +uint8_t* LLUI_DISPLAY_IMPL_flush(MICROUI_GraphicsContext* gc, + uint8_t* srcAddr, uint32_t xmin, + uint32_t ymin, uint32_t xmax, + uint32_t ymax) +{ +#ifdef HARD_FLUSH_DBG + PRINTF("x_offset: %d\r\n", flush_region.x_offset); + PRINTF("y_offset: %d\r\n", flush_region.y_offset); + PRINTF("width: %d\r\n", flush_region.width); + PRINTF("height: %d\r\n", flush_region.height); +#endif + + xmin = flush_region.x_offset; + ymin = flush_region.y_offset; + xmax = xmin + flush_region.width - 1; + ymax = ymin + flush_region.height - 1; + + uint32_t number_pixels = flush_region.width * flush_region.height; + +#ifdef HARD_FLUSH_DBG + PRINTF("xmin: %d\r\n", xmin); + PRINTF("ymin: %d\r\n", ymin); + PRINTF("xmax: %d\r\n", xmax); + PRINTF("ymax: %d\r\n", ymax); + PRINTF("\r\n"); +#endif + + disp_sup_flush(srcAddr, xmin, ymin, xmax, ymax, number_pixels); + + LLUI_DISPLAY_flushDone(false); + return srcAddr; +} + +void LLUI_DISPLAY_IMPL_binarySemaphoreTake(void* sem){ + xSemaphoreTake((xSemaphoreHandle)sem, portMAX_DELAY); +} + +void LLUI_DISPLAY_IMPL_binarySemaphoreGive(void* sem, bool under_isr) { + if (under_isr) { + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR((xSemaphoreHandle)sem, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken != pdFALSE) { + // Force a context switch here. + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } + } + else { + xSemaphoreGive((xSemaphoreHandle)sem); + } +} + +void Java_com_microej_partial_support_PartialBufferNatives_setFlushLimits(jint xOffset, jint yOffset, + jint width, jint height) +{ + flush_region.x_offset = xOffset; + flush_region.y_offset = yOffset; + flush_region.width = width; + flush_region.height = height; +} + +int32_t Java_com_microej_partial_support_PartialBufferNatives_getBufferHeight() +{ + return LCD_VIRTUAL_BUF_HEIGHT; +} diff --git a/bsp/projects/microej/ui/src/LLUI_DISPLAY_HEAP_impl.c b/bsp/projects/microej/ui/src/LLUI_DISPLAY_HEAP_impl.c new file mode 100644 index 0000000..22ea4b1 --- /dev/null +++ b/bsp/projects/microej/ui/src/LLUI_DISPLAY_HEAP_impl.c @@ -0,0 +1,107 @@ +/* + * C + * + * Copyright 2021-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief This MicroUI images heap allocator replaces the default allocator embedded in the + * MicroUI Graphics Engine. It is using a best fit allocator and provides some additional APIs + * to retrieve the heap information: total space, free space, number of blocks allocated. + * + * @see LLUI_DISPLAY_impl.h file comment + * @author MicroEJ Developer Team + * @version 2.0.1 + * @date 16 December 2022 + * @since MicroEJ UI Pack 13.1.0 + */ + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include "microui_heap.h" +#include "BESTFIT_ALLOCATOR.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// -------------------------------------------------------------------------------- +// Macros and Defines +// -------------------------------------------------------------------------------- + +/* + * @brief The best fit allocator stores a main header of 68 bytes (0x44) in the heap. + */ +#define BESTFITALLOCATOR_HEADER_SIZE (68) + +/* + * @brief The best fit allocator stores a header before an allocated block and a footer + * after. The header holds the block size plus the header and footer sizes. This macro + * retrieves the block full size (header + data + footer). + */ +#define BESTFITALLOCATOR_BLOCK_SIZE(block) ((*(uint32_t*)((block)-sizeof(uint32_t))) & 0x7ffffff) + +// -------------------------------------------------------------------------------- +// Private fields +// -------------------------------------------------------------------------------- + +static BESTFIT_ALLOCATOR image_heap; +static uint32_t heap_size; +static uint32_t free_space; +static uint32_t allocated_blocks_number; + +// -------------------------------------------------------------------------------- +// microui_heap.h functions +// -------------------------------------------------------------------------------- + +uint32_t MICROUI_HEAP_total_space(void) { + return heap_size; +} + +uint32_t MICROUI_HEAP_free_space(void) { + return free_space; +} + +uint32_t MICROUI_HEAP_number_of_allocated_blocks(void) { + return allocated_blocks_number; +} + +// -------------------------------------------------------------------------------- +// LLUI_DISPLAY_impl.h functions +// -------------------------------------------------------------------------------- + + +void LLUI_DISPLAY_IMPL_image_heap_initialize(uint8_t* heap_start, uint8_t* heap_limit) { + heap_size = heap_limit - heap_start - BESTFITALLOCATOR_HEADER_SIZE; + free_space = heap_size; + BESTFIT_ALLOCATOR_new(&image_heap); + BESTFIT_ALLOCATOR_initialize(&image_heap, (int32_t)heap_start, (int32_t)heap_limit); +} + +uint8_t* LLUI_DISPLAY_IMPL_image_heap_allocate(uint32_t size) { + uint8_t* addr = (uint8_t*)BESTFIT_ALLOCATOR_allocate(&image_heap, (int32_t)size); + + if ((uint8_t*)0 != addr) { + free_space -= BESTFITALLOCATOR_BLOCK_SIZE(addr); + allocated_blocks_number++; + } + return addr; +} + +void LLUI_DISPLAY_IMPL_image_heap_free(uint8_t* block) { + free_space += BESTFITALLOCATOR_BLOCK_SIZE(block); + allocated_blocks_number--; + BESTFIT_ALLOCATOR_free(&image_heap, (void*)block); +} + +// -------------------------------------------------------------------------------- +// EOF +// -------------------------------------------------------------------------------- + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/ui/src/LLUI_INPUT.c b/bsp/projects/microej/ui/src/LLUI_INPUT.c new file mode 100644 index 0000000..f796ba8 --- /dev/null +++ b/bsp/projects/microej/ui/src/LLUI_INPUT.c @@ -0,0 +1,46 @@ +/** + * Copyright 2022-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#include "LLUI_INPUT_impl.h" +#include "microej.h" +#include "touch_manager.h" +#include "interrupts.h" +#include "FreeRTOS.h" +#include "semphr.h" +#include "LLUI_INPUT_impl.h" + +static xSemaphoreHandle g_sem_input; + +/* API -----------------------------------------------------------------------*/ + +void LLUI_INPUT_IMPL_initialize(void) +{ + g_sem_input = xSemaphoreCreateBinary(); + xSemaphoreGive(g_sem_input); + + TOUCH_MANAGER_initialize(); +} + +int32_t LLUI_INPUT_IMPL_getInitialStateValue(int32_t stateMachinesID, int32_t stateID) +{ + // no state on this BSP + return 0; +} + +void LLUI_INPUT_IMPL_enterCriticalSection() +{ + if (interrupt_is_in() == MICROEJ_FALSE) + { + xSemaphoreTake(g_sem_input, portMAX_DELAY); + } +} + +void LLUI_INPUT_IMPL_leaveCriticalSection() +{ + if (interrupt_is_in() == MICROEJ_FALSE) + { + xSemaphoreGive(g_sem_input); + } +} diff --git a/bsp/projects/microej/ui/src/LLUI_INPUT_LOG_impl.c b/bsp/projects/microej/ui/src/LLUI_INPUT_LOG_impl.c new file mode 100644 index 0000000..57bf67f --- /dev/null +++ b/bsp/projects/microej/ui/src/LLUI_INPUT_LOG_impl.c @@ -0,0 +1,188 @@ +/* + * C + * + * Copyright 2021-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief This MicroUI FIFO (queue) logger replaces the default logger embedded in the + * MicroUI Input Engine. For each queue event, it stores the event's data size. This + * allows to be able to decode the event when LLUI_INPUT_dump() is called. + * + * This logger does not interpret the event: it just recognizes the event's first + * element and event's data. When an event is detected, the logger calls + * microui_event_decoder.h functions. + * + * @see LLUI_INPUT_impl.h file comment + * @author MicroEJ Developer Team + * @version 2.0.1 + * @date 16 December 2022 + * @since MicroEJ UI Pack 13.1.0 + */ + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include +#include + +// implements some LLUI_INPUT_impl functions +#include "LLUI_INPUT_impl.h" + +// deport event description to another file +#include "microui_event_decoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MICROUIEVENTDECODER_ENABLED + +// ----------------------------------------------------------------------------- +// Macros and Defines +// ----------------------------------------------------------------------------- + +/* + * @brief Logger's array size. The MicroUI FIFO cannot be higher than this size. + */ +#define QUEUE_LOG_MAX_SIZE 500 + +// ----------------------------------------------------------------------------- +// Global Variables +// ----------------------------------------------------------------------------- + +/* + * @brief Pointer on event's data decoder. + */ +static MICROUI_EVENT_DECODER_decode_event_data fct_decode_data; + +/* + * @brief Logger array where store the MicroUI event metadata. + */ +static uint8_t queue_log[QUEUE_LOG_MAX_SIZE]; + +/* + * @brief true when a new event is logged, false when the event's data is logged. + */ +static bool queue_is_first_element; + +/* + * @brief Current event to decode. + */ +static uint32_t dump_current_event; + +// ----------------------------------------------------------------------------- +// LLUI_INPUT_impl.h functions +// ----------------------------------------------------------------------------- + +void LLUI_INPUT_IMPL_log_queue_init(uint32_t length) { + assert(length <= (uint32_t)QUEUE_LOG_MAX_SIZE); + (void)memset((void*)queue_log, 0, length); + queue_is_first_element = true; +} + +void LLUI_INPUT_IMPL_log_queue_full(uint32_t data) { + // queue is full, nothing to log + (void)data; +} + +void LLUI_INPUT_IMPL_log_queue_add(uint32_t data, uint32_t index, uint32_t remaining_elements, uint32_t queue_length) { + (void)data; + (void)queue_length; + + if (queue_is_first_element) { + // start new event: set the event size in array + queue_log[index] = (uint8_t)(remaining_elements + (uint32_t)1); + } + else { + // continue previous event: drop data + queue_log[index] = 0; + } + + // prepare next log + queue_is_first_element = remaining_elements == (uint32_t)0; +} + +void LLUI_INPUT_IMPL_log_queue_replace(uint32_t old, uint32_t data, uint32_t index, uint32_t queue_length) { + // previous event has been replaced, nothing to log + (void)old; + (void)data; + (void)index; + (void)queue_length; +} + +void LLUI_INPUT_IMPL_log_queue_read(uint32_t data, uint32_t index) { + // event has been read, nothing to log + (void)data; + (void)index; +} + +void LLUI_INPUT_IMPL_log_dump(bool log_type, uint32_t log, uint32_t index) { + if (log_type) { + // log is an event or a data event + + if ((uint32_t)0 != queue_log[index]) { + // it is a new event to decode + dump_current_event = log; + + // reset data decoder + fct_decode_data = NULL; + + // decode event (decoder can give a data decoder) + MICROUI_EVENT_DECODER_decode_event(log, index, &fct_decode_data); + } + else if (NULL != fct_decode_data) { + // decode data of previous event + fct_decode_data(dump_current_event, log, index); + } + else { + // cannot decode this element: drop it + MICROUI_EVENT_DECODER_drop_data(log, index); + } + } + else { + // log is a status: see function API comment. + + switch(log) { + + case 0: + // start of dump (events already consumed) + MICROUI_EVENT_DECODER_describe_dump_start(); + MICROUI_EVENT_DECODER_describe_dump_past(); + + // drop first element if it is not an event + fct_decode_data = NULL; + break; + + case 1: + // continue dump (events not consumed yet) + MICROUI_EVENT_DECODER_describe_dump_future(); + break; + + case 2: + // dump java objects + MICROUI_EVENT_DECODER_describe_dump_events_objects(); + break; + + case 3: + default: + // end of dump + MICROUI_EVENT_DECODER_describe_dump_end(); + break; + } + } +} + +#endif // MICROUIEVENTDECODER_ENABLED + +// ----------------------------------------------------------------------------- +// EOF +// ----------------------------------------------------------------------------- + +#ifdef __cplusplus +} +#endif + diff --git a/bsp/projects/microej/ui/src/LLUI_PAINTER_impl.c b/bsp/projects/microej/ui/src/LLUI_PAINTER_impl.c new file mode 100644 index 0000000..35e8886 --- /dev/null +++ b/bsp/projects/microej/ui/src/LLUI_PAINTER_impl.c @@ -0,0 +1,484 @@ + +/* + * Copyright 2020-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * @file + * @brief This file implements all MicroUI drawing native functions. + * @see LLUI_PAINTER_impl.h file comment + * @author MicroEJ Developer Team + * @version 2.0.1 + * @date 16 December 2022 + * @since MicroEJ UI Pack 13.0.0 + */ + +// -------------------------------------------------------------------------------- +// Includes +// -------------------------------------------------------------------------------- + +// implements LLUI_PAINTER_impl functions +#include "LLUI_PAINTER_impl.h" + +// calls ui_drawing functions +#include "ui_drawing.h" + +// use graphical engine functions to synchronize drawings +#include "LLUI_DISPLAY.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// -------------------------------------------------------------------------------- +// Macros and Defines +// -------------------------------------------------------------------------------- + +// macros to log a drawing +#define LOG_DRAW_START(fn) LLUI_DISPLAY_logDrawingStart(CONCAT_DEFINES(LOG_DRAW_, fn)) +#define LOG_DRAW_END(fn) LLUI_DISPLAY_logDrawingEnd(CONCAT_DEFINES(LOG_DRAW_, fn)) + +/* + * LOG_DRAW_EVENT logs identifiers + */ +#define LOG_DRAW_writePixel 1 +#define LOG_DRAW_drawLine 2 +#define LOG_DRAW_drawHorizontalLine 3 +#define LOG_DRAW_drawVerticalLine 4 +#define LOG_DRAW_drawRectangle 5 +#define LOG_DRAW_fillRectangle 6 +#define LOG_DRAW_drawRoundedRectangle 8 +#define LOG_DRAW_fillRoundedRectangle 9 +#define LOG_DRAW_drawCircleArc 10 +#define LOG_DRAW_fillCircleArc 11 +#define LOG_DRAW_drawEllipseArc 12 +#define LOG_DRAW_fillEllipseArc 13 +#define LOG_DRAW_drawEllipse 14 +#define LOG_DRAW_fillEllipse 15 +#define LOG_DRAW_drawCircle 16 +#define LOG_DRAW_fillCircle 17 +#define LOG_DRAW_drawARGB 18 +#define LOG_DRAW_drawImage 19 + +// -------------------------------------------------------------------------------- +// Private functions +// -------------------------------------------------------------------------------- + +/* + * Checks given bound to fit in bound limits: 0 and max (excluded). Updates size and + * origin in consequence + */ +static inline void _check_bound(jint max, jint* bound, jint* size, jint* origin) { + if (*bound < 0) { + *size += *bound; // decrease size + *origin -= *bound; // increase origin + *bound = 0; + } + + if ((*bound + *size) > max) { + *size = max - *bound; // decrease size + } +} + +// -------------------------------------------------------------------------------- +// LLUI_PAINTER_impl.h functions +// -------------------------------------------------------------------------------- + +void LLUI_PAINTER_IMPL_writePixel(MICROUI_GraphicsContext* gc, jint x, jint y) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_writePixel)) { + DRAWING_Status status; + LOG_DRAW_START(writePixel); + if (LLUI_DISPLAY_isPixelInClip(gc, x, y)) { + LLUI_DISPLAY_configureClip(gc, false/* point is in clip */); + status = UI_DRAWING_writePixel(gc, x, y); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(writePixel); + } + // else: pixel out of clip: nothing to do (requestDrawing() has not been called) +} + +void LLUI_PAINTER_IMPL_drawLine(MICROUI_GraphicsContext* gc, jint startX, jint startY, jint endX, jint endY) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawLine)) { + LOG_DRAW_START(drawLine); + // cannot reduce/clip line: may be endX < startX and / or endY < startY + LLUI_DISPLAY_setDrawingStatus(UI_DRAWING_drawLine(gc, startX, startY, endX, endY)); + LOG_DRAW_END(drawLine); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_drawHorizontalLine(MICROUI_GraphicsContext* gc, jint x, jint y, jint length) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawHorizontalLine)) { + DRAWING_Status status; + LOG_DRAW_START(drawHorizontalLine); + + jint x1 = x; + jint x2 = x + length - 1; + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((length > 0) && LLUI_DISPLAY_clipHorizontalLine(gc, &x1, &x2, y)) { + LLUI_DISPLAY_configureClip(gc, false /* line has been clipped */); + status = UI_DRAWING_drawHorizontalLine(gc, x1, x2, y); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawHorizontalLine); + } + // else: line out of clip: nothing to do (requestDrawing() has not been called) +} + +void LLUI_PAINTER_IMPL_drawVerticalLine(MICROUI_GraphicsContext* gc, jint x, jint y, jint length) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawVerticalLine)) { + DRAWING_Status status; + LOG_DRAW_START(drawVerticalLine); + + jint y1 = y; + jint y2 = y + length - 1; + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((length > 0) && LLUI_DISPLAY_clipVerticalLine(gc, &y1, &y2, x)) { + LLUI_DISPLAY_configureClip(gc, false /* line has been clipped */); + status = UI_DRAWING_drawVerticalLine(gc, x, y1, y2); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawVerticalLine); + } + // else: line out of clip: nothing to do (requestDrawing() has not been called) +} + +void LLUI_PAINTER_IMPL_drawRectangle(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawRectangle)) { + DRAWING_Status status; + LOG_DRAW_START(drawRectangle); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((width > 0) && (height > 0)) { + jint x1 = x; + jint x2 = x + width - 1; + jint y1 = y; + jint y2 = y + height - 1; + + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRectangleInClip(gc, x1, y1, x2, y2)); + status = UI_DRAWING_drawRectangle(gc, x1, y1, x2, y2); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawRectangle); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_fillRectangle(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_fillRectangle)) { + DRAWING_Status status; + LOG_DRAW_START(fillRectangle); + + jint x1 = x; + jint x2 = x + width - 1; + jint y1 = y; + jint y2 = y + height - 1; + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((width > 0) && (height) > 0 && LLUI_DISPLAY_clipRectangle(gc, &x1, &y1, &x2, &y2)) { + LLUI_DISPLAY_configureClip(gc, false /* rectangle has been clipped */); + status = UI_DRAWING_fillRectangle(gc, x1, y1, x2, y2); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(fillRectangle); + } + // else: rectangle out of clip: nothing to do (requestDrawing() has not been called) +} + +void LLUI_PAINTER_IMPL_drawRoundedRectangle(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jint cornerEllipseWidth, jint cornerEllipseHeight) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawRoundedRectangle)) { + DRAWING_Status status; + LOG_DRAW_START(drawRoundedRectangle); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((width > 0) && (height > 0)) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height)); + status = UI_DRAWING_drawRoundedRectangle(gc, x, y, width, height, cornerEllipseWidth, cornerEllipseHeight); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawRoundedRectangle); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_fillRoundedRectangle(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jint cornerEllipseWidth, jint cornerEllipseHeight) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_fillRoundedRectangle)) { + DRAWING_Status status; + LOG_DRAW_START(fillRoundedRectangle); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((width > 0) && (height > 0)) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height)); + status = UI_DRAWING_fillRoundedRectangle(gc, x, y, width, height, cornerEllipseWidth, cornerEllipseHeight); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(fillRoundedRectangle); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_drawCircleArc(MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter, jfloat startAngle, jfloat arcAngle) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawCircleArc)) { + DRAWING_Status status; + LOG_DRAW_START(drawCircleArc); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((diameter > 0) && ((int32_t)arcAngle != 0)) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, diameter, diameter)); + status = UI_DRAWING_drawCircleArc(gc, x, y, diameter, startAngle, arcAngle); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawCircleArc); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_drawEllipseArc(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jfloat startAngle, jfloat arcAngle) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawEllipseArc)) { + DRAWING_Status status; + LOG_DRAW_START(drawEllipseArc); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((width > 0) && (height > 0) && ((int32_t)arcAngle != 0)) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height)); + status = UI_DRAWING_drawEllipseArc(gc, x, y, width, height, startAngle, arcAngle); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawEllipseArc); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_fillCircleArc(MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter, jfloat startAngle, jfloat arcAngle) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_fillCircleArc)) { + DRAWING_Status status; + LOG_DRAW_START(fillCircleArc); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((diameter > 0) && ((int32_t)arcAngle != 0)) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, diameter, diameter)); + status = UI_DRAWING_fillCircleArc(gc, x, y, diameter, startAngle, arcAngle); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(fillCircleArc); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_fillEllipseArc(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jfloat startAngle, jfloat arcAngle) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_fillEllipseArc)) { + DRAWING_Status status; + LOG_DRAW_START(fillEllipseArc); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((width > 0) && (height > 0) && ((int32_t)arcAngle != 0)) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height)); + status = UI_DRAWING_fillEllipseArc(gc, x, y, width, height, startAngle, arcAngle); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(fillEllipseArc); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_drawEllipse(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawEllipse)) { + DRAWING_Status status; + LOG_DRAW_START(drawEllipse); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((width > 0) && (height > 0)) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height)); + status = UI_DRAWING_drawEllipse(gc, x, y, width, height); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawEllipse); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_fillEllipse(MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_fillEllipse)) { + DRAWING_Status status; + LOG_DRAW_START(fillEllipse); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if ((width > 0) && (height > 0)) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height)); + status = UI_DRAWING_fillEllipse(gc, x, y, width, height); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(fillEllipse); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_drawCircle(MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawCircle)) { + DRAWING_Status status; + LOG_DRAW_START(drawCircle); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if (diameter > 0) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, diameter, diameter)); + status = UI_DRAWING_drawCircle(gc, x, y, diameter); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawCircle); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_fillCircle(MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_fillCircle)) { + DRAWING_Status status; + LOG_DRAW_START(fillCircle); + + // tests on size and clip are performed after suspend to prevent to perform it several times + if (diameter > 0) { + // cannot reduce rectangle; can only check if it is fully in clip + LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, diameter, diameter)); + status = UI_DRAWING_fillCircle(gc, x, y, diameter); + } + else { + // requestDrawing() has been called and accepted: notify the end of empty drawing + status = DRAWING_DONE; + } + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(fillCircle); + } + // else: refused drawing +} + +void LLUI_PAINTER_IMPL_drawImage(MICROUI_GraphicsContext* gc, MICROUI_Image* img, jint regionX, jint regionY, jint width, jint height, jint x, jint y, jint alpha) { + if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&LLUI_PAINTER_IMPL_drawImage)) { + DRAWING_Status status = DRAWING_DONE; + LOG_DRAW_START(drawImage); + + // tests on parameters and clip are performed after suspend to prevent to perform it several times + if (!LLUI_DISPLAY_isClosed(img) && (alpha > 0)) { + + // sanity check on opacity + jint l_alpha = (alpha > 255) ? 255 : alpha; + + // compute inside image bounds + _check_bound(img->width, ®ionX, &width, &x); + _check_bound(img->height, ®ionY, &height, &y); + + // compute inside graphics context bounds + _check_bound(gc->image.width, &x, &width, ®ionX); + _check_bound(gc->image.height, &y, &height, ®ionY); + + if ((width > 0) && (height > 0) && LLUI_DISPLAY_clipRegion(gc, ®ionX, ®ionY, &width, &height, &x, &y)) { + + LLUI_DISPLAY_configureClip(gc, false /* region has been clipped */); + + if (gc->image.format == img->format) { + // source & destination have got the same pixels memory representation + + if (0xff /* fully opaque */ == l_alpha && !LLUI_DISPLAY_isTransparent(img)) { + // copy source on destination without applying an opacity (beware about the overlapping) + status = UI_DRAWING_copyImage(gc, img, regionX, regionY, width, height, x, y); + } + else if (img == &gc->image){ + // blend source on itself applying an opacity (beware about the overlapping) + status = UI_DRAWING_drawRegion(gc, regionX, regionY, width, height, x, y, l_alpha); + } + else { + // blend source on destination applying an opacity + status = UI_DRAWING_drawImage(gc, img, regionX, regionY, width, height, x, y, l_alpha); + } + } + else { + // draw source on destination applying an opacity + status = UI_DRAWING_drawImage(gc, img, regionX, regionY, width, height, x, y, l_alpha); + } + } + // else: nothing to do + } + // else: nothing to do + + // requestDrawing() has been called and accepted: notify the end of empty drawing + LLUI_DISPLAY_setDrawingStatus(status); + LOG_DRAW_END(drawImage); + } + // else: refused drawing +} + +// -------------------------------------------------------------------------------- +// EOF +// -------------------------------------------------------------------------------- + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/ui/src/event_generator.c b/bsp/projects/microej/ui/src/event_generator.c new file mode 100644 index 0000000..723c113 --- /dev/null +++ b/bsp/projects/microej/ui/src/event_generator.c @@ -0,0 +1,38 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +/* + * This file converts the input events in MicroUI Event Generator events. + */ + +/* Includes ------------------------------------------------------------------*/ + +#include "LLUI_INPUT.h" + +// this h file is created by buildSystemMicroUI step +#include "microui_constants.h" + +/* Defines -------------------------------------------------------------------*/ + + +/* Touch ---------------------------------------------------------------------*/ + +int32_t EVENT_GENERATOR_touch_pressed(int32_t x, int32_t y) +{ + return LLUI_INPUT_sendTouchPressedEvent(MICROUI_EVENTGEN_TOUCH, x, y); +} + +int32_t EVENT_GENERATOR_touch_moved(int32_t x, int32_t y) +{ + return LLUI_INPUT_sendTouchMovedEvent(MICROUI_EVENTGEN_TOUCH, x, y); +} + +int32_t EVENT_GENERATOR_touch_released(void) +{ + return LLUI_INPUT_sendTouchReleasedEvent(MICROUI_EVENTGEN_TOUCH); +} diff --git a/bsp/projects/microej/ui/src/framerate.c b/bsp/projects/microej/ui/src/framerate.c new file mode 100644 index 0000000..e7a7ff6 --- /dev/null +++ b/bsp/projects/microej/ui/src/framerate.c @@ -0,0 +1,94 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include +#include "framerate_impl.h" + +/* Globals -------------------------------------------------------------------*/ + +#ifdef FRAMERATE_ENABLED +static uint32_t framerate_schedule_time = 0; // means "not initialised" +static uint32_t framerate_counter; +static uint32_t framerate_last; +#endif + +/* API -----------------------------------------------------------------------*/ + +int32_t framerate_init(int32_t schedule_time) +{ +#ifdef FRAMERATE_ENABLED + + if (framerate_schedule_time == 0) // means "not initialized" + { + // fix globals + framerate_schedule_time = schedule_time; + framerate_counter = 0; + framerate_last = 0; + + int32_t ret = framerate_impl_start_task(); + if (ret != FRAMERATE_OK) + { + // an error has occurred + return ret; + } + } + // else: no error because already initialized + + return FRAMERATE_OK; + +#else + return FRAMERATE_ERROR; +#endif +} + +void framerate_increment(void) +{ +#ifdef FRAMERATE_ENABLED + framerate_counter++; +#endif +} + +uint32_t framerate_get(void) +{ +#ifdef FRAMERATE_ENABLED + return framerate_last; +#else + return 0; +#endif +} + +void framerate_task_work(void) +{ +#ifdef FRAMERATE_ENABLED + while(1) + { + // sleep during n milliseconds + framerate_impl_sleep(framerate_schedule_time); + + // update global counter + framerate_last = (int32_t)((float)framerate_counter * ((float)((float)1000 / (float)framerate_schedule_time))); + + // reset framerate counter + framerate_counter = 0; + } +#endif +} + +/* Java API ------------------------------------------------------------------*/ + +int32_t javaFramerateInit(int32_t schedule_time) +{ + return framerate_init(schedule_time); +} + +uint32_t javaFramerateGet(void) +{ + return framerate_get(); +} diff --git a/bsp/projects/microej/ui/src/framerate_impl_FreeRTOS.c b/bsp/projects/microej/ui/src/framerate_impl_FreeRTOS.c new file mode 100644 index 0000000..6ff1a36 --- /dev/null +++ b/bsp/projects/microej/ui/src/framerate_impl_FreeRTOS.c @@ -0,0 +1,53 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/* + * Implementation for FreeRTOS + */ + +#include "framerate_conf.h" +#ifdef FRAMERATE_ENABLED + +/* Includes ------------------------------------------------------------------*/ + +#include "FreeRTOS.h" +#include "task.h" +#include "framerate_impl.h" + +/* Defines -------------------------------------------------------------------*/ + +#define FRAMERATE_STACK_SIZE ( 512 ) +#define FRAMERATE_TASK_PRIORITY ( 3 ) +#define FRAMERATE_TASK_STACK_SIZE FRAMERATE_STACK_SIZE/4 + +/* Private API ---------------------------------------------------------------*/ + +static void _framerate_task(void * pvParameters) +{ + // launch framerate job + framerate_task_work(); + // job end, cleanup resources + vTaskDelete(xTaskGetCurrentTaskHandle()); +} + +/* API -----------------------------------------------------------------------*/ + +int32_t framerate_impl_start_task(void) +{ + BaseType_t xReturn = xTaskCreate( _framerate_task, "FRAMERATE", FRAMERATE_TASK_STACK_SIZE, NULL, FRAMERATE_TASK_PRIORITY, NULL ); + return xReturn == pdPASS ? FRAMERATE_OK : FRAMERATE_ERROR; +} + +void framerate_impl_sleep(uint32_t ms) +{ + TickType_t ticks = ms / portTICK_PERIOD_MS; + vTaskDelay(ticks ? ticks : 1); /* Minimum delay = 1 tick */ + return; +} + +#endif + diff --git a/bsp/projects/microej/ui/src/interrupts.c b/bsp/projects/microej/ui/src/interrupts.c new file mode 100644 index 0000000..0c5d48c --- /dev/null +++ b/bsp/projects/microej/ui/src/interrupts.c @@ -0,0 +1,29 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +/* Includes ------------------------------------------------------------------*/ + +#include "interrupts.h" +#include "FreeRTOS.h" + +/* Public functions ----------------------------------------------------------*/ + +uint8_t interrupt_is_in(void) +{ + BaseType_t is_in_ISR; + + is_in_ISR = xPortIsInsideInterrupt(); + if (is_in_ISR == pdTRUE) + { + return MICROEJ_TRUE; + } + else + { + return MICROEJ_FALSE; + } +} diff --git a/bsp/projects/microej/ui/src/microui_event_decoder.c b/bsp/projects/microej/ui/src/microui_event_decoder.c new file mode 100644 index 0000000..3f99c39 --- /dev/null +++ b/bsp/projects/microej/ui/src/microui_event_decoder.c @@ -0,0 +1,426 @@ +/* + * C + * + * Copyright 2021-2022 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +/** + * @file + * @brief This MicroUI Events decoder describes the events to the standard output stream. + * + * @see LLUI_INPUT_LOG_impl.c file comment + * @author MicroEJ Developer Team + * @version 2.0.1 + * @date 16 December 2022 + * @since MicroEJ UI Pack 13.1.0 + */ + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +// calls Microui events decoder functions +#include "microui_event_decoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MICROUIEVENTDECODER_ENABLED + +// ----------------------------------------------------------------------------- +// Macros and Defines +// ----------------------------------------------------------------------------- + +/* + * @brief Default traces. + */ +#define DESCRIBE_EVENT_GENERATOR(event) (LLUI_DEBUG_TRACE(" (event generator %u)", EVENT_GENERATOR_ID(event))) +#define DESCRIBE_EOL() (LLUI_DEBUG_TRACE("\n")) + +/* + * @brief Decodes MicroUI event. + */ +#define EVENT_DATA(event) ((uint16_t)(event)) +#define EVENT_GENERATOR_ID(event) ((uint8_t)((event) >> 16)) + +/* + * @brief Decodes MicroUI Command event. + */ +#define COMMAND_GET(event) EVENT_DATA(event) + +/* + * @brief Decodes MicroUI Buttons event. + */ +#define BUTTON_ACTION_PRESSED 0 +#define BUTTON_ACTION_RELEASED 1 +#define BUTTON_ACTION_LONG 2 +#define BUTTON_ACTION_REPEATED 3 +#define BUTTON_ACTION_CLICK 4 +#define BUTTON_ACTION_DOUBLECLICK 5 +#define BUTTON_ACTION(event) ((uint8_t)((event) >> 8)) +#define BUTTON_ID(event) ((uint8_t)(event)) + +/* + * @brief Decodes MicroUI Pointer event. + */ +#define POINTER_ACTION_MOVE 6 +#define POINTER_ACTION_DRAG 7 +#define POINTER_X(data) (((data) >> 16) & 0xfff) +#define POINTER_Y(data) ((data) & 0xfff) +#define POINTER_TYPE(data) (((data) >> 31) & 0x1) + +/* + * @brief Decodes MicroUI user event. + */ +#define USEREVENT_SIZE(event) EVENT_DATA(event) + +// ----------------------------------------------------------------------------- +// Internal functions +// ----------------------------------------------------------------------------- + +static void decode_event_command(uint32_t event, uint32_t index, MICROUI_EVENT_DECODER_decode_event_data* fct_data_decoder) { + (void)index; + (void)fct_data_decoder; + + LLUI_DEBUG_TRACE("Command "); + + uint8_t command = (uint8_t)COMMAND_GET(event); + + switch(command) { + case 0: + LLUI_DEBUG_TRACE("ESC"); + break; + case 1: + LLUI_DEBUG_TRACE("BACK"); + break; + case 2: + LLUI_DEBUG_TRACE("UP"); + break; + case 3: + LLUI_DEBUG_TRACE("DOWN"); + break; + case 4: + LLUI_DEBUG_TRACE("LEFT"); + break; + case 5: + LLUI_DEBUG_TRACE("RIGHT"); + break; + case 6: + LLUI_DEBUG_TRACE("SELECT"); + break; + case 7: + LLUI_DEBUG_TRACE("CANCEL"); + break; + case 8: + LLUI_DEBUG_TRACE("HELP"); + break; + case 9: + LLUI_DEBUG_TRACE("MENU"); + break; + case 10: + LLUI_DEBUG_TRACE("EXIT"); + break; + case 11: + LLUI_DEBUG_TRACE("START"); + break; + case 12: + LLUI_DEBUG_TRACE("STOP"); + break; + case 13: + LLUI_DEBUG_TRACE("PAUSE"); + break; + case 14: + LLUI_DEBUG_TRACE("RESUME"); + break; + case 15: + LLUI_DEBUG_TRACE("COPY"); + break; + case 16: + LLUI_DEBUG_TRACE("CUT"); + break; + case 17: + LLUI_DEBUG_TRACE("PASTE"); + break; + case 18: + LLUI_DEBUG_TRACE("CLOCKWISE"); + break; + case 19: + LLUI_DEBUG_TRACE("ANTICLOCKWISE"); + break; + case 20: + LLUI_DEBUG_TRACE("PREVIOUS"); + break; + case 21: + LLUI_DEBUG_TRACE("NEXT"); + break; + default: + LLUI_DEBUG_TRACE("0x%02x", command); + break; + } + + DESCRIBE_EVENT_GENERATOR(event); + DESCRIBE_EOL(); +} + +static void decode_event_button(uint32_t event, uint32_t index, MICROUI_EVENT_DECODER_decode_event_data* fct_data_decoder) { + (void)index; + (void)fct_data_decoder; + + LLUI_DEBUG_TRACE("Button %u ", BUTTON_ID(event)); + uint8_t action = BUTTON_ACTION(event); + + switch(action) { + case BUTTON_ACTION_PRESSED: + LLUI_DEBUG_TRACE("pressed"); + break; + case BUTTON_ACTION_RELEASED: + LLUI_DEBUG_TRACE("released"); + break; + case BUTTON_ACTION_LONG: + LLUI_DEBUG_TRACE("long"); + break; + case BUTTON_ACTION_REPEATED: + LLUI_DEBUG_TRACE("repeated"); + break; + case BUTTON_ACTION_CLICK: + LLUI_DEBUG_TRACE("click"); + break; + case BUTTON_ACTION_DOUBLECLICK: + LLUI_DEBUG_TRACE("double-click"); + break; + default: + LLUI_DEBUG_TRACE("unknown action: %u", action); + break; + } + + DESCRIBE_EVENT_GENERATOR(event); + DESCRIBE_EOL(); +} + +#ifdef MICROUIEVENTDECODER_EVENTGEN_TOUCH +/* + * @brief Input pointer event holds a data that contains x and y. + */ +static void decode_event_pointer_data(uint32_t event, uint32_t data, uint32_t index) { + (void)event; + + LLUI_DEBUG_TRACE("[%02u: 0x%08x] at %u,%u (", index, data, POINTER_X(data), POINTER_Y(data)); + if (0 == POINTER_TYPE(data)) { + LLUI_DEBUG_TRACE("absolute)"); + } + else { + LLUI_DEBUG_TRACE("relative)"); + } + + DESCRIBE_EOL(); +} +#endif // MICROUIEVENTDECODER_EVENTGEN_TOUCH + +static void decode_event_pointer(uint32_t event, uint32_t index, MICROUI_EVENT_DECODER_decode_event_data* fct_data_decoder) { + (void)index; + (void)fct_data_decoder; + + LLUI_DEBUG_TRACE("Pointer "); + uint8_t action = BUTTON_ACTION(event); + + switch(action) { + case BUTTON_ACTION_PRESSED: + LLUI_DEBUG_TRACE("pressed"); + break; + case BUTTON_ACTION_RELEASED: + LLUI_DEBUG_TRACE("released"); + break; + case BUTTON_ACTION_LONG: + LLUI_DEBUG_TRACE("long"); + break; + case BUTTON_ACTION_REPEATED: + LLUI_DEBUG_TRACE("repeated"); + break; + case BUTTON_ACTION_CLICK: + LLUI_DEBUG_TRACE("click"); + break; + case BUTTON_ACTION_DOUBLECLICK: + LLUI_DEBUG_TRACE("double-click"); + break; + case POINTER_ACTION_MOVE: + LLUI_DEBUG_TRACE("moved"); + break; + case POINTER_ACTION_DRAG: + LLUI_DEBUG_TRACE("dragged"); + break; + default: + LLUI_DEBUG_TRACE("unknown action: %u", action); + break; + } + + DESCRIBE_EVENT_GENERATOR(event); + DESCRIBE_EOL(); +} + +static void decode_event_state(uint32_t event, uint32_t index, MICROUI_EVENT_DECODER_decode_event_data* fct_data_decoder) { + (void)index; + (void)fct_data_decoder; + + LLUI_DEBUG_TRACE("TODO %s 0x%08x\n", __FUNCTION__, event); +} + +/* + * @brief Decodes the input events: the events sent by the BSP. To decode the events, + * the decoder must know the event generators identifier defined during the MicroEJ + * platform build. These identifiers are available in microui_constants.h. + * + * @see microui_event_decoder_conf.h + */ +static void decode_event_input(uint32_t event, uint32_t index, MICROUI_EVENT_DECODER_decode_event_data* fct_data_decoder) { + LLUI_DEBUG_TRACE("Input event: "); + + uint8_t generator_id = EVENT_GENERATOR_ID(event); + + switch(generator_id) { + +#ifdef MICROUIEVENTDECODER_EVENTGEN_COMMAND + case MICROUI_EVENTGEN_COMMANDS: + decode_event_command(event, index, fct_data_decoder); + break; +#endif // MICROUIEVENTDECODER_EVENTGEN_COMMAND + +#ifdef MICROUIEVENTDECODER_EVENTGEN_BUTTONS + case MICROUIEVENTDECODER_EVENTGEN_BUTTONS: + decode_event_button(event, index, fct_data_decoder); + break; +#endif // MICROUIEVENTDECODER_EVENTGEN_BUTTONS + +#ifdef MICROUIEVENTDECODER_EVENTGEN_TOUCH + case MICROUIEVENTDECODER_EVENTGEN_TOUCH: + *fct_data_decoder = decode_event_pointer_data; + decode_event_pointer(event, index, fct_data_decoder); + break; +#endif // MICROUIEVENTDECODER_EVENTGEN_TOUCH + + default: + LLUI_DEBUG_TRACE("unknown "); + DESCRIBE_EVENT_GENERATOR(event); + DESCRIBE_EOL(); + break; + } +} + +static void decode_event_user_data(uint32_t event, uint32_t data, uint32_t index) { + (void)event; + LLUI_DEBUG_TRACE(" [%02u] 0x%08x\n", index, data); +} + +static void decode_event_user(uint32_t event, uint32_t index, MICROUI_EVENT_DECODER_decode_event_data* fct_data_decoder) { + LLUI_DEBUG_TRACE("User input event"); + + uint8_t size = (uint8_t)USEREVENT_SIZE(event); + if (size > (uint32_t)1) { + LLUI_DEBUG_TRACE("s (size = %u)", size); + } + DESCRIBE_EVENT_GENERATOR(event); + LLUI_DEBUG_TRACE(": "); + + *fct_data_decoder = decode_event_user_data; +} + +// ----------------------------------------------------------------------------- +// API +// ----------------------------------------------------------------------------- + + +void MICROUI_EVENT_DECODER_describe_dump_start(void) { + LLUI_DEBUG_TRACE("============================== MicroUI FIFO Dump ===============================\n"); +} + +void MICROUI_EVENT_DECODER_describe_dump_past(void) { + LLUI_DEBUG_TRACE("---------------------------------- Old Events ----------------------------------\n"); +} + +void MICROUI_EVENT_DECODER_describe_dump_future(void) { + LLUI_DEBUG_TRACE("---------------------------------- New Events ----------------------------------\n"); +} + +void MICROUI_EVENT_DECODER_describe_dump_events_objects(void) { + LLUI_DEBUG_TRACE("--------------------------- New Events' Java objects ---------------------------\n"); +} + +void MICROUI_EVENT_DECODER_describe_dump_end(void) { + LLUI_DEBUG_TRACE("================================================================================\n"); +} + +void MICROUI_EVENT_DECODER_drop_data(uint32_t data, uint32_t index) { + LLUI_DEBUG_TRACE("[%02u: 0x%08x] garbage\n", index, data); +} + +void MICROUI_EVENT_DECODER_decode_event(uint32_t event, uint32_t index, MICROUI_EVENT_DECODER_decode_event_data* fct_data_decoder) { + LLUI_DEBUG_TRACE("[%02u: 0x%08x] ", index, event); + + uint8_t event_type = (uint8_t)(event >> 24); + + switch(event_type) { + case 0x00: + decode_event_command(event, index, fct_data_decoder); + break; + case 0x01: + decode_event_button(event, index, fct_data_decoder); + break; + case 0x02: + decode_event_pointer(event, index, fct_data_decoder); + break; + case 0x03: + decode_event_state(event, index, fct_data_decoder); + break; + case 0x04: + // not used + break; + case 0x05: + LLUI_DEBUG_TRACE("Call serially (Runnable index = %u)\n", EVENT_DATA(event)); + break; + case 0x06: + LLUI_DEBUG_TRACE("MicroUI STOP\n"); + break; + case 0x07: + decode_event_input(event, index, fct_data_decoder); + break; + case 0x08: + LLUI_DEBUG_TRACE("Display SHOW Displayable (Displayable index = %u)\n", EVENT_DATA(event)); + break; + case 0x09: + LLUI_DEBUG_TRACE("Display HIDE Displayable (Displayable index = %u)\n", EVENT_DATA(event)); + break; + case 0x0a: + // not used + break; + case 0x0b: + LLUI_DEBUG_TRACE("Display FLUSH\n"); + break; + case 0x0c: + LLUI_DEBUG_TRACE("Display FORCE FLUSH\n"); + break; + case 0x0d: + LLUI_DEBUG_TRACE("Display REPAINT Displayable (Displayable index = %u)\n", EVENT_DATA(event)); + break; + case 0x0e: + LLUI_DEBUG_TRACE("Display REPAINT Current Displayable\n"); + break; + case 0x0f: + LLUI_DEBUG_TRACE("Display KF SWITCH Display\n"); + break; + default: + decode_event_user(event, index, fct_data_decoder); + break; + } +} + +#endif // MICROUIEVENTDECODER_ENABLED + +// ----------------------------------------------------------------------------- +// EOF +// ----------------------------------------------------------------------------- + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/ui/src/panel_func.c b/bsp/projects/microej/ui/src/panel_func.c new file mode 100644 index 0000000..1fa1145 --- /dev/null +++ b/bsp/projects/microej/ui/src/panel_func.c @@ -0,0 +1,77 @@ +/* + * Copyright 2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "panel_func.h" +#include "fsl_lcdic.h" + +#if (defined(APP_PANEL_ADAFRUIT_2_8_CAPTATIVE) && APP_PANEL_ADAFRUIT_2_8_CAPTATIVE) +#include "fsl_ili9341.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void APP_LcdWriteCmdData(uint8_t cmd, const uint8_t *data, uint32_t dataLen) +{ + lcdic_tx_xfer_t xfer; + + if (0U == dataLen) + { + LCDIC_SendCommandBlocking(LCDIC, cmd); + } + else + { + xfer.cmd = cmd; + xfer.teSyncMode = kLCDIC_TeNoSync; + xfer.trxTimeoutMode = kLCDIC_ShortTimeout; + xfer.dataFormat = kLCDIC_DataFormatByte; + xfer.dataLen = dataLen; + xfer.txData = data; + + LCDIC_SendDataArrayBlocking(LCDIC, &xfer); + } +} + +#if (defined(APP_PANEL_ADAFRUIT_2_8_CAPTATIVE) && APP_PANEL_ADAFRUIT_2_8_CAPTATIVE) +void APP_InitPanel(void) +{ + FT9341_Init1(APP_LcdWriteCmdData); + + APP_LcdWriteCmdData(ILI9341_CMD_MAC, (const uint8_t[]){0x28U}, 1u); +} + +void APP_PanelSelectRegion(uint16_t startX, uint16_t startY, uint16_t endX, uint16_t endY) +{ + uint8_t data[4]; + /*Column addresses*/ + data[0] = (startX >> 8) & 0xFF; + data[1] = startX & 0xFF; + data[2] = (endX >> 8) & 0xFF; + data[3] = endX & 0xFF; + APP_LcdWriteCmdData(ILI9341_CMD_COLADDR, data, 4u); + + /*Page addresses*/ + data[0] = (startY >> 8) & 0xFF; + data[1] = startY & 0xFF; + data[2] = (endY >> 8) & 0xFF; + data[3] = endY & 0xFF; + APP_LcdWriteCmdData(ILI9341_CMD_PAGEADDR, data, 4u); +} +#endif diff --git a/bsp/projects/microej/ui/src/touch_helper.c b/bsp/projects/microej/ui/src/touch_helper.c new file mode 100644 index 0000000..9ae2c40 --- /dev/null +++ b/bsp/projects/microej/ui/src/touch_helper.c @@ -0,0 +1,125 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +/* + * The MicroUI framework is using an internal buffer to store the inputs events. The event + * will not be added if the internal events buffer is full. In this case the input driver + * has to adapt itself in order to not send a future invalid event. For instance, if a + * PRESSED event is not sent, the input driver has not to send a REPEAT or RELEASE event. + * So it may have a distinction between the real input state and the "software" input + * state. + * + * When an event has not been managed because the system events queue is full: + * - increase the size of the system events queue (see Memory page of the application launcher + * - limit rate of events of your drivers (for example, calibrate buttons to send an event + * at most every X ms) + */ + +/* Includes ------------------------------------------------------------------*/ + +#include "LLUI_INPUT.h" +#include "microej.h" +#include "touch_helper_configuration.h" +#include "event_generator.h" + +/* Defines -------------------------------------------------------------------*/ + +// Number of pixels to generate a move after a press +#ifndef FIRST_MOVE_PIXEL_LIMIT +#error "Please set the define FIRST_MOVE_PIXEL_LIMIT in touch_helper_configuration.h" +#endif + +// Number of pixels to generate a move after a move +#ifndef MOVE_PIXEL_LIMIT +#error "Please set the define MOVE_PIXEL_LIMIT in touch_helper_configuration.h" +#endif + +#define DIFF(a,b) ((a) < (b) ? (b-a) : (a-b)) +#define KEEP_COORD(p,n,limit) (DIFF(p,n) <= limit ? MICROEJ_FALSE : MICROEJ_TRUE) +#define KEEP_PIXEL(px,x,py,y,limit) (KEEP_COORD(px,x,limit) || KEEP_COORD(py,y,limit)) +#define KEEP_FIRST_MOVE(px,x,py,y) (KEEP_PIXEL(px,x,py,y, FIRST_MOVE_PIXEL_LIMIT)) +#define KEEP_MOVE(px,x,py,y) (KEEP_PIXEL(px,x,py,y, MOVE_PIXEL_LIMIT)) + +/* Global --------------------------------------------------------------------*/ + +static uint8_t touch_pressed = MICROEJ_FALSE; +static uint8_t touch_moved = MICROEJ_FALSE; // == MICROEJ_TRUE after the first "move" event +static uint16_t previous_touch_x, previous_touch_y; + +/* API -----------------------------------------------------------------------*/ + +void TOUCH_HELPER_pressed(int32_t x, int32_t y) +{ + // here, pen is down for sure + + if (touch_pressed == MICROEJ_TRUE) + { + // pen was down => move event + + // keep pixel according first "move" event or not + int keep_pixel; + if(touch_moved == MICROEJ_TRUE) + { + keep_pixel = KEEP_MOVE(previous_touch_x, x, previous_touch_y, y); + } + else + { + keep_pixel = KEEP_FIRST_MOVE(previous_touch_x, x, previous_touch_y, y); + } + + if (keep_pixel == MICROEJ_TRUE) + { + // store the new pixel + previous_touch_x = x; + previous_touch_y = y; + touch_moved = MICROEJ_TRUE; + + // send a MicroUI touch event (don't care if event is lost) + EVENT_GENERATOR_touch_moved(x, y); + } + // else: same position; no need to send an event + } + else + { + // pen was up => press event + if (EVENT_GENERATOR_touch_pressed(x, y) == LLUI_INPUT_OK) + { + // the event has been managed: we can store the new touch state + // touch is pressed now + previous_touch_x = x; + previous_touch_y = y; + touch_pressed = MICROEJ_TRUE; + touch_moved = MICROEJ_FALSE; + } + // else: event has been lost: stay in "release" state + } +} + +void TOUCH_HELPER_moved(int32_t x, int32_t y) +{ + // manage this move like a press event in order to check "software" touch state + TOUCH_HELPER_pressed(x, y); +} + +void TOUCH_HELPER_released(void) +{ + // here, pen is up for sure + + if (touch_pressed == MICROEJ_TRUE) + { + // pen was down => release event + if (EVENT_GENERATOR_touch_released() == LLUI_INPUT_OK) + { + // the event has been managed: we can store the new touch state + // touch is released now + touch_pressed = MICROEJ_FALSE; + } + // else: event has been lost: stay in "press | move" state + } + // else: pen was already up +} diff --git a/bsp/projects/microej/ui/src/touch_manager.c b/bsp/projects/microej/ui/src/touch_manager.c new file mode 100644 index 0000000..fdf8969 --- /dev/null +++ b/bsp/projects/microej/ui/src/touch_manager.c @@ -0,0 +1,137 @@ +/* + * C + * + * Copyright 2015-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + + +/* Includes ------------------------------------------------------------------*/ + +#include "FreeRTOS.h" +#include "semphr.h" +#include "task.h" +#include "touch_helper.h" +#include "touch_manager.h" +#include "microej.h" +#include "display_support.h" +#include "fsl_debug_console.h" + +// ----------------------------------------------------------------------------- +// Macros and Defines +// ----------------------------------------------------------------------------- + +#define BOARD_TOUCH_I2C Driver_I2C2 +#define BOARD_TOUCH_I2C_IRQ FLEXCOMM2_IRQn + +/* + * @brief Task delay (in ms) between detecting a multiple pressed events + */ +#define TOUCH_DELAY 30 + +/* + * @brief Task stack size + */ +#define TOUCH_STACK_SIZE (1024) +#define TOUCH_TASK_PRIORITY ( 9 ) + +// ----------------------------------------------------------------------------- +// Static Variables +// ----------------------------------------------------------------------------- + +//static ft6x06_handle_t touch_handle; + +/* + * @brief vglite operation semaphore + */ +#if 0 +static SemaphoreHandle_t touch_interrupt_sem; +#endif + +/* Private API ---------------------------------------------------------------*/ + +/** + * Touch thread routine + */ +static void __touch_manager_task(void *pvParameters); + + +/* API -----------------------------------------------------------------------*/ + +void TOUCH_MANAGER_initialize(void) +{ + DEMO_InitTouch(); + +#define TOUCH_PRIORITY (5) + + /* Create the touch screen task */ + if (pdPASS != xTaskCreate(__touch_manager_task, "Touch screen task", TOUCH_STACK_SIZE, NULL, TOUCH_PRIORITY, NULL)) { + PRINTF("Touch task initialization failed\r\n"); + assert(false); + } +} + +void TOUCH_MANAGER_interrupt(void) +{ + // use busy-way mechanism for the time being +#if 0 + uint32_t intStat = GPIO_PortGetInterruptStatus(GPIO, TOUCH_INTERRUPT_PORT, kGPIO_InterruptA); + if (intStat & (1UL << TOUCH_INTERRUPT_PIN)) + { + GPIO_PortClearInterruptFlags(GPIO, TOUCH_INTERRUPT_PORT, kGPIO_InterruptA, + (1UL << TOUCH_INTERRUPT_PIN)); + + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(touch_interrupt_sem, &xHigherPriorityTaskWoken); + if(xHigherPriorityTaskWoken != pdFALSE ) + { + // Force a context switch here. + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } + } +#endif +} + +// ----------------------------------------------------------------------------- +// Internal functions +// ----------------------------------------------------------------------------- + + +// See the section 'Internal function definitions' for the function documentation +static void __touch_manager_read(void) +{ + //touch_event_t touch_event; + int pressed = -1; + int touch_x; + int touch_y; + + DEMO_ReadTouch(&pressed, &touch_x, &touch_y); + if (pressed == 0) + { +#ifdef TOUCH_DBG + PRINTF("touch_manager_read %d [%d %d]\r\n", pressed, touch_x, touch_y); +#endif + TOUCH_HELPER_pressed(touch_x, touch_y); + } + else if (pressed == 1) + { +#ifdef TOUCH_DBG + PRINTF("touch_manager_read %d [%d %d]\r\n", pressed, touch_x, touch_y); +#endif + TOUCH_HELPER_released(); + } +} + +// See the section 'Internal function definitions' for the function documentation +static void __touch_manager_task(void *pvParameters) +{ + while (1) + { + /* Suspend ourselves */ + //xSemaphoreTake(touch_interrupt_sem, portMAX_DELAY); + + /* We have been woken up, lets work ! */ + __touch_manager_read(); + vTaskDelay(TOUCH_DELAY); + } +} diff --git a/bsp/projects/microej/util/inc/microej_async_worker.h b/bsp/projects/microej/util/inc/microej_async_worker.h new file mode 100644 index 0000000..706f353 --- /dev/null +++ b/bsp/projects/microej/util/inc/microej_async_worker.h @@ -0,0 +1,332 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef MICROEJ_ASYNC_WORKER_H +#define MICROEJ_ASYNC_WORKER_H + +/** + * @file + * @brief Asynchronous Worker API. + * This library helps writing SNI functions that must be executed asynchronously. + * + * The execution of an SNI function prevents the other Java thread to be scheduled. That's why blocking native functions + * or long native functions should be executed asynchronously. + *

+ * An async worker is declared statically using the MICROEJ_ASYNC_WORKER_worker_declare() macro and started with + * the MICROEJ_ASYNC_WORKER_initialize() function. + * Jobs are allocated using MICROEJ_ASYNC_WORKER_allocate_job() and scheduled with MICROEJ_ASYNC_WORKER_async_exec(). + *

+ * Typical usage consists in declaring: + * - for each SNI function, a structure that contains the parameters of the function, + * - an union of all the previously declared structures, + * - the async worker using MICROEJ_ASYNC_WORKER_worker_declare() macro. + *

+ * For example, if we have to implement asynchronously the following two SNI functions : + * @code + * int foo(int i, int j); + * void bar(int i); + * @endcode + * + *

+ * Then we will declare the async worker as following: + * @code + * // foo() parameters structure + * typedef struct { + * int i; + * int j; + * int result; + * } foo_param_t; + * + * // bar() parameters structure + * typedef struct { + * int i; + * } bar_param_t; + * + * // union of all the parameters structures + * typedef union { + * foo_param_t foo; + * bar_param_t bar; + * ... + * } my_worker_param_t; + * + * // Declare the worker and the task that will execute it + * MICROEJ_ASYNC_WORKER_worker_declare(my_worker, MY_WORKER_JOB_COUNT, my_worker_param_t, MY_WORKER_WAITING_LIST_SIZE); + * OSAL_task_stack_declare(my_worker_stack, MY_WORKER_STACK_SIZE); + * + * void initialize(){ + * MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_initialize(&my_worker, "My Worker", my_worker_stack, MY_WORKER_PRIORITY); + * if(status != MICROEJ_ASYNC_WORKER_OK){ + * ... + * } + * ... + * } + * + * int foo(int i, int j){ + * MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_allocate_job(&my_worker, (SNI_callback)foo); + * if(job != NULL){ + * foo_param_t* params = (foo_param_t*)job->params; + * params->i = i; + * params->j = j; + * + * MICROEJ_ASYNC_WORKER_status_t status = MICROEJ_ASYNC_WORKER_async_exec(&my_worker, job, foo_action, (SNI_callback)foo_on_done); + * if(status != MICROEJ_ASYNC_WORKER_OK){ + * // Error + * MICROEJ_ASYNC_WORKER_free_job(&my_worker, job); + * } + * } + * // If an error occurred, then an exception is pending, + * // otherwise the current thread is suspended. + * // In any case, the returned value is not used. + * return -1; + * } + * + * void foo_action(MICROEJ_ASYNC_WORKER_job_t* job){ + * foo_param_t* params = (foo_param_t*)job->params; + * + * int i = params->i; + * int j = params->j; + * + * ... + * + * params->result = result; + * } + * + * int foo_on_done(int i, int j){ + * MICROEJ_ASYNC_WORKER_job_t* job = MICROEJ_ASYNC_WORKER_get_job_done(); + * foo_param_t* params = (foo_param_t*)job->params; + * + * int result = params->result; + * MICROEJ_ASYNC_WORKER_free_job(&my_worker, job); + * + * return result; + * } + * + * ... + * @endcode + * + * + * @author MicroEJ Developer Team + * @version 0.4.0 + * @date 17 June 2022 + */ + +#include +#include "sni.h" +#include "osal.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** @brief Return codes list. */ +typedef enum { + MICROEJ_ASYNC_WORKER_OK, + MICROEJ_ASYNC_WORKER_ERROR, + MICROEJ_ASYNC_WORKER_INVALID_ARGS +} MICROEJ_ASYNC_WORKER_status_t; + + +/** @brief See struct MICROEJ_ASYNC_WORKER_job. */ +typedef struct MICROEJ_ASYNC_WORKER_job MICROEJ_ASYNC_WORKER_job_t; + +/** @brief Pointer to a function to call asynchronously. */ +typedef void (*MICROEJ_ASYNC_WORKER_action_t)(MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief A job to execute in a worker. + * + * Jobs are allocated using MICROEJ_ASYNC_WORKER_allocate_job() + * and freed using MICROEJ_ASYNC_WORKER_free_job(). + */ +struct MICROEJ_ASYNC_WORKER_job{ + /** + * @brief Pointers to the parameters. + * + * This pointer is initialized by the system and references an union of type _param_type (value given to MICROEJ_ASYNC_WORKER_worker_declare()). + * This pointer field must not be modified but the content of the referenced union can be modified. + */ + void* params; + /** @brief Structure internal data. Must not be modified. */ + struct { + MICROEJ_ASYNC_WORKER_action_t action; // Pointer to the action to execute asynchronously. + int32_t thread_id; // Id of the Java thread that is waiting for this job to complete ; SNI_ERROR if no thread is waiting. + MICROEJ_ASYNC_WORKER_job_t* next_free_job; // Next in the free jobs linked list. + } _intern; +}; + +/** + * @brief An async worker. + * + * Workers are declared using the MICROEJ_ASYNC_WORKER_worker_declare() macro and + * initialized with MICROEJ_ASYNC_WORKER_initialize(). + *

+ * All the fields of this structure are internal data and must not be modified. + */ +typedef struct { + int32_t job_count; // Maximum number of jobs. + MICROEJ_ASYNC_WORKER_job_t* free_jobs; // Linked list of free jobs + void* params; // Pointer to params array. Length of this array is job_count. + int32_t params_sizeof; // Size of the params union + int32_t waiting_threads_length; // Length of the waiting_threads array + int32_t* waiting_threads; // Array of waiting threads (circular list) + uint16_t waiting_thread_offset; // Offset of the first waiting thread. If equals to free_waiting_thread_offset: no waiting thread + uint16_t free_waiting_thread_offset; // Offset of the first free slot in waiting_threads array + OSAL_queue_handle_t jobs_queue; // Linked list of jobs + OSAL_task_handle_t task; // The task that executes this worker. + OSAL_mutex_handle_t mutex; // Mutex used for critical sections. +} MICROEJ_ASYNC_WORKER_handle_t; + +/** + * @brief Declares a worker named _name. + * + * This macro must be used outside of any function so the worker is declared as a global variable. + * + * @param _name name of the worker variable. + * @param _job_count maximum number of jobs that can be allocated for this worker. Must be greater than 0. + * @param _param_type type of the union of all the parameters structures + * @param _waiting_list_size Maximum Java thread that can be suspended on MICROEJ_ASYNC_WORKER_allocate_job() when no job is available. Must be greater than 0. + */ +#define MICROEJ_ASYNC_WORKER_worker_declare(_name, _job_count, _param_type, _waiting_list_size)\ + _param_type _name ## _params[_job_count];\ + MICROEJ_ASYNC_WORKER_job_t _name ## _jobs[_job_count];\ + int32_t _name ## _waiting_threads[_waiting_list_size+1];\ + MICROEJ_ASYNC_WORKER_handle_t _name = {\ + .job_count = _job_count,\ + .free_jobs = _name ## _jobs,\ + .params = _name ## _params,\ + .params_sizeof = sizeof(_param_type),\ + .waiting_threads_length = _waiting_list_size+1,\ + .waiting_threads = _name ## _waiting_threads,\ + .waiting_thread_offset = 0,\ + .free_waiting_thread_offset = 0\ + } + + +/** + * @brief Initializes and starts a worker previously declared with MICROEJ_ASYNC_WORKER_worker_declare() macro. + * + * @param[in] async_worker the worker to initialize. Declared with MICROEJ_ASYNC_WORKER_worker_declare() macro. + * @param[in] name worker name. + * @param[in] stack worker task stack declared using OSAL_task_stack_declare() macro. + * @param[in] priority worker task priority. + * + * @return MICROEJ_ASYNC_WORKER_INVALID_ARGS if given worker has not been correctly declared. + * Returns MICROEJ_ASYNC_WORKER_ERROR if worker task or queue creation fails. + * Returns MICROEJ_ASYNC_WORKER_OK on success. + */ +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_initialize(MICROEJ_ASYNC_WORKER_handle_t* async_worker, uint8_t* name, OSAL_task_stack_t stack, int32_t priority); + +/** + * @brief Allocates a new job for the given worker. + * + * If a job is available, returns a reference to the job. + *

+ * If there is no job available, the current Java thread is suspended, added to the waiting list and NULL + * is returned. Then, when a job is available, the Java thread is resumed and the function + * sni_retry_callback is called. + * Usually the sni_retry_callback function argument is the current SNI function itself (i.e. the function + * that is currently calling MICROEJ_ASYNC_WORKER_allocate_job()). + *

+ * If the waiting list is full, an SNI exception is thrown using SNI_throwNativeIOException() and + * NULL is returned. Size of the waiting list is defined when declaring the worker. + *

+ * params field of the returned job is a pointer to a type T where T is + * the value of the argument _param_type given to the MICROEJ_ASYNC_WORKER_worker_declare() + * macro. + *

+ * This function must be called within the virtual machine task. + * + * @param[in] async_worker the worker in which to allocate a job. + * @param[in] sni_retry_callback if the current Java thread has been suspended, this function is called when it is resumed. + * + * @return A job on success or NULL if no job is available. + */ +MICROEJ_ASYNC_WORKER_job_t* MICROEJ_ASYNC_WORKER_allocate_job(MICROEJ_ASYNC_WORKER_handle_t* async_worker, SNI_callback sni_retry_callback); + + +/** + * @brief Frees a job previously allocated with MICROEJ_ASYNC_WORKER_allocate_job(). + * + * This function must be called when and only when the given job has been executed and the result retrieved. This is usually done + * in the on_done_callback given to MICROEJ_ASYNC_WORKER_async_exec(). After calling this function the given job and its + * parameters must not be used anymore. + *

+ * This function must be called within the virtual machine task. + * + * @param[in] async_worker the worker used to allocate the given job. + * @param[in] job the job to free. Must have been allocated with MICROEJ_ASYNC_WORKER_allocate_job(). + * + * @return MICROEJ_ASYNC_WORKER_OK on success, otherwise returns the error status + * MICROEJ_ASYNC_WORKER_ERROR. + */ +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_free_job(MICROEJ_ASYNC_WORKER_handle_t* async_worker, MICROEJ_ASYNC_WORKER_job_t* job); + +/** + * @brief Executes the given job asynchronously. + * + * This function does not block and returns immediately but it suspends the execution of the current Java thread + * until the job is finished. + *

+ * When the job is finished, the SNI callback on_done_callback is called before going back to Java. + * If the job is not used anymore, the callback must released it explicitly by calling + * MICROEJ_ASYNC_WORKER_free_job(). + *

+ * If an error happens, an SNI exception is thrown using SNI_throwNativeIOException() and the error + * status MICROEJ_ASYNC_WORKER_ERROR is returned. In this case, the SNI callback + * on_done_callback is not called and the job must be released explicitly by calling + * MICROEJ_ASYNC_WORKER_free_job(). + *

+ * This function must be called within the virtual machine task. + * + * @param[in] async_worker the worker used to execute the given job. Must be the same than the one used to allocate the job. + * @param[in] job the job to execute. Must have been allocated with MICROEJ_ASYNC_WORKER_allocate_job(). + * @param[in] action the function to execute asynchronously. + * @param[in] on_done_callback the SNI_callback called when the job is done. + * + * @return MICROEJ_ASYNC_WORKER_OK on success, otherwise returns the error status + * MICROEJ_ASYNC_WORKER_ERROR. + */ +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_async_exec(MICROEJ_ASYNC_WORKER_handle_t* async_worker, MICROEJ_ASYNC_WORKER_job_t* job, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done_callback); + +/** + * @brief Executes the given job asynchronously. + * + * This function does not block and returns immediately. + *

+ * When the job is finished, the job is automatically released by the async worker thread. + *

+ * If an error happens, an SNI exception is thrown using SNI_throwNativeIOException() and the error + * status MICROEJ_ASYNC_WORKER_ERROR is returned. In this case, the job must be released explicitly + * by calling MICROEJ_ASYNC_WORKER_free_job(). + *

+ * This function must be called within the virtual machine task. + * + * @param[in] async_worker the worker used to execute the given job. Must be the same than the one used to allocate the job. + * @param[in] job the job to execute. Must have been allocated with MICROEJ_ASYNC_WORKER_allocate_job(). + * @param[in] action the function to execute asynchronously. + * + * @return MICROEJ_ASYNC_WORKER_OK on success, otherwise returns the error status + * MICROEJ_ASYNC_WORKER_ERROR. + */ +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_async_exec_no_wait(MICROEJ_ASYNC_WORKER_handle_t* async_worker, MICROEJ_ASYNC_WORKER_job_t* job, MICROEJ_ASYNC_WORKER_action_t action); + +/** + * @brief Returns the job that has been executed. + * + * This function must be called after the execution of a job in the function passed as on_done_callback + * argument to MICROEJ_ASYNC_WORKER_async_exec(). + * + * @return the job that has been executed asynchronously or NULL if not called from an on_done_callback. + */ +MICROEJ_ASYNC_WORKER_job_t* MICROEJ_ASYNC_WORKER_get_job_done(void); + +#ifdef __cplusplus + } +#endif + +#endif // MICROEJ_ASYNC_WORKER_H + diff --git a/bsp/projects/microej/util/inc/microej_pool.h b/bsp/projects/microej/util/inc/microej_pool.h new file mode 100644 index 0000000..a9e14c9 --- /dev/null +++ b/bsp/projects/microej/util/inc/microej_pool.h @@ -0,0 +1,109 @@ +/* + * C + * + * Copyright 2020-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ memory pool implementation + * @author MicroEJ Developer Team + * @version 0.1.0 + */ + +/* + * The module provide function to simply manage a + * Fixed memory pool size. + */ + +#ifndef MICROEJ_POOL_H +#define MICROEJ_POOL_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @brief list of status for one element */ +typedef enum +{ + POOL_FREE, + POOL_USED +}POOL_item_status_t; + +/** @brief define pool type */ +typedef struct { + void * pv_first_item; /**< pointer on first element in pool */ + POOL_item_status_t * puc_item_status; /**< pointer on array status item */ + unsigned int ui_size_of_item; /**< size of one element */ + unsigned int uc_num_item_in_pool; /**< number of element in pool */ +}POOL_ctx_t; + +/** @brief list of module constant */ +typedef enum +{ + POOL_NO_ERROR, + POOL_ERROR_IN_ENTRY_PARAMETERS, + POOL_NO_SPACE_AVAILABLE, + POOL_ITEM_NOT_FOUND_IN_POOL, +}POOL_status_t; + +/** @brief Define a function prototype used to compare a pool item with a characteristic */ +typedef bool (*microej_pool_compare_functor_t)(void *item, void *characteristic); + + +/** @brief pool declaration macro */ +#define POOL_declare(name, pool_type, size) \ + static pool_type name ## _pool_array[size]; \ + static POOL_item_status_t name ## _pool_item_status[size]; \ + static POOL_ctx_t name = \ + { \ + name ## _pool_array, \ + name ## _pool_item_status, \ + sizeof(pool_type), \ + sizeof(name ## _pool_array) / sizeof(pool_type) \ + } + +/** + * @brief function to reserved one place in pool + * + * @param[in] _st_pool_ctx pool context + * @param[in,out] _ppv_item_reserved pointer on reserved item + * + * @return @see POOL_status_t + */ +POOL_status_t POOL_reserve_f(POOL_ctx_t * _st_pool_ctx, + void ** _ppv_item_reserved); + +/** + * @brief Get an item in according to a comparison function and a characteristic. + * + * @param[in] _st_pool_ctx pool context + * @param[in,out] _ppv_item_retrieved pointer on item to be retrieved + * @param[in] compare_to functor on the comparison function. + * @param[in] characteristic characteristic on which the comparison will occurred. + * + * @return @see POOL_status_t + */ +POOL_status_t POOL_get_f(POOL_ctx_t * _st_pool_ctx, void ** _ppv_item_retrieved, + microej_pool_compare_functor_t compare_to, void* characteristic); + +/** + * @brief function to free an item of the pool + * + * @param[in,out] _st_pool_ctx pool context + * @param[in] _pv_item_to_free pointer item to free + * + * @return @see POOL_status_t + */ +POOL_status_t POOL_free_f(POOL_ctx_t * _st_pool_ctx, + void * const _pv_item_to_free); + +#ifdef __cplusplus +} +#endif + +#endif /* MICROEJ_POOL_H */ diff --git a/bsp/projects/microej/util/inc/osal.h b/bsp/projects/microej/util/inc/osal.h new file mode 100644 index 0000000..581c87c --- /dev/null +++ b/bsp/projects/microej/util/inc/osal.h @@ -0,0 +1,309 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief OS Abstraction Layer API + * @author MicroEJ Developer Team + * @version 1.0.1 + * @date 17 June 2022 + */ + +#ifndef OSAL_H +#define OSAL_H + +#include + +/* + * Each OSAL port has a unique osal_portmacro.h header file. + * + * This file must declare the following macros: + * - OSAL_task_stack_declare: + * @brief Declare a task stack. + * @param[in] _name name of the variable that defines the stack. + * @param[in] _size size of the stack in bytes. _size must be compile time constant value. + * OSAL_task_stack_declare(_name, _size); + * - OSAL_queue_declare: + * @brief Declare a queue. + * @param[in] _name name of the variable that defines the queue. + * @param[in] _size number of items that can be stored in the queue. _size must be compile time constant value. + * OSAL_queue_declare(_name, _size); + * + * Both macros must be compile-time constants for static initialization. + * + * This file must declare the following type: + * - OSAL_task_stack_t: OS task stack + * - OSAL_queue_t: OS queue + */ +#include "osal_portmacro.h" + +#if !defined(OSAL_task_stack_declare) || !defined(OSAL_queue_declare) + #error "osal_portmacro.h doesn't comply with specification." +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +/** @brief define an infinite time */ +#define OSAL_INFINITE_TIME 0xFFFFFFFF + +/** @brief return code list */ +typedef enum { + OSAL_OK, + OSAL_ERROR, + OSAL_NOMEM, + OSAL_WRONG_ARGS, + OSAL_NOT_IMPLEMENTED, + OSAL_NOT_SUPPORTED +} OSAL_status_t; + +#ifndef OSAL_CUSTOM_TYPEDEF + +/** @brief task function entry point */ +typedef void* (*OSAL_task_entry_point_t)(void *args); + +/** @brief OS task handle */ +typedef void* OSAL_task_handle_t; + +/** @brief OS queue handle */ +typedef void* OSAL_queue_handle_t; + +/** @brief OS counter semaphore handle */ +typedef void* OSAL_counter_semaphore_handle_t; + +/** @brief OS binary semaphore handle */ +typedef void* OSAL_binary_semaphore_handle_t; + +/** @brief OS mutex handle */ +typedef void* OSAL_mutex_handle_t; + +#endif + +/** + * @brief Create an OS task and start it. + * + * @param[in] entry_point function called at task startup + * @param[in] name the task name + * @param[in] stack task stack declared using OSAL_task_stack_declare() macro + * @param[in] priority task priority + * @param[in] parameters task entry parameters. NULL if no entry parameters + * @param[in,out] handle pointer on a task handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_task_create(OSAL_task_entry_point_t entry_point, uint8_t* name, OSAL_task_stack_t stack, int32_t priority, + void* parameters, OSAL_task_handle_t* handle); + +/** + * @brief Delete an OS task and start it. + * + * @param[in] handle pointer on the task handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_task_delete(OSAL_task_handle_t* handle); + +/** + * @brief Get the handle of the current OS task. + * + * @param[in,out] handle pointer on a task handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_task_get_current(OSAL_task_handle_t* handle); + +/** + * @brief Create an OS queue with a predefined queue size. + * + * @param[in] name queue name + * @param[in,out] handle pointer on a queue handle + * @param[in] queue structure containing address and size declared using OSAL_queue_declare() macro + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_queue_create(uint8_t* name, OSAL_queue_handle_t* handle, OSAL_queue_t queue); + +/** + * @brief Delete an OS queue. + * + * @param[in] handle pointer on the queue handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_queue_delete(OSAL_queue_handle_t* handle); + +/** + * @brief Post a message in an OS queue. + * + * @param[in] handle pointer on the queue handle + * @param[in] msg message to post in the message queue + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_queue_post(OSAL_queue_handle_t* handle, void* msg); + +/** + * @brief Fetch a message from an OS queue. Blocks until a message arrived or a timeout occurred. + * + * @param[in] handle pointer on the queue handle + * @param[in,out] msg message fetched from the OS queue + * @param[in] timeout maximum time to wait for message arrival, OSAL_INFINITE_TIME for infinite timeout + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_queue_fetch(OSAL_queue_handle_t* handle, void** msg, uint32_t timeout); + +/** + * @brief Create an OS counter semaphore with a semaphore count initial value. + * + * @param[in] name counter semaphore name + * @param[in] initial_count counter semaphore initial count value + * @param[in] max_count counter semaphore maximum count value + * @param[in,out] handle pointer on a counter semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_counter_semaphore_create(uint8_t* name, uint32_t initial_count, uint32_t max_count, + OSAL_counter_semaphore_handle_t* handle); + +/** + * @brief Delete an OS counter semaphore. + * + * @param[in] handle pointer on the counter semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_counter_semaphore_delete(OSAL_counter_semaphore_handle_t* handle); + +/** + * @brief Take operation on OS counter semaphore. Block the current task until counter semaphore become available or timeout + * occurred. Decrease the counter semaphore count value by 1 and block the current task if count value equals to 0. + * + * @param[in] handle pointer on the counter semaphore handle + * @param[in] timeout maximum time to wait until the counter semaphore become available, OSAL_INFINITE_TIME for infinite timeout + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_counter_semaphore_take(OSAL_counter_semaphore_handle_t* handle, uint32_t timeout); + +/** + * @brief Give operation on OS counter semaphore. Increase the counter semaphore count value by 1 and unblock the current task if + * count value equals to 0. + * + * @param[in] handle pointer on the counter semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_counter_semaphore_give(OSAL_counter_semaphore_handle_t* handle); + +/** + * @brief Create an OS binary semaphore with a semaphore count initial value (0 or 1). + * + * @param[in] name counter semaphore name + * @param[in] initial_count counter semaphore initial count value + * @param[in,out] handle pointer on a binary semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_binary_semaphore_create(uint8_t* name, uint32_t initial_count, OSAL_binary_semaphore_handle_t* handle); + +/** + * @brief Delete an OS binary semaphore. + * + * @param[in] handle pointer on the binary semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_binary_semaphore_delete(OSAL_binary_semaphore_handle_t* handle); + +/** + * @brief Take operation on OS binary semaphore. Block the current task until binary semaphore become available or timeout + * occurred. Decrease the binary semaphore count value by 1 and block the current task if count value equals to 0. + * + * @param[in] handle pointer on the binary semaphore handle + * @param[in] timeout maximum time to wait until the binary semaphore become available, OSAL_INFINITE_TIME for infinite timeout + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_binary_semaphore_take(OSAL_binary_semaphore_handle_t* handle, uint32_t timeout); + +/** + * @brief Give operation on OS binary semaphore. Increase the binary semaphore count value by 1 and unblock the current task if + * count value equals to 0. + * + * @param[in] handle pointer on the binary semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_binary_semaphore_give(OSAL_binary_semaphore_handle_t* handle); + +/** + * @brief Create an OS mutex. + * + * @param[in] name mutex name + * @param[in,out] handle pointer on a mutex handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_mutex_create(uint8_t* name, OSAL_mutex_handle_t* handle); + +/** + * @brief Delete an OS mutex. + * + * @param[in] handle pointer on the mutex handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_mutex_delete(OSAL_mutex_handle_t* handle); + +/** + * @brief Take operation on OS mutex. + * + * @param[in] handle pointer on the mutex handle + * @param[in] timeout maximum time to wait until the mutex become available, OSAL_INFINITE_TIME for infinite timeout + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_mutex_take(OSAL_mutex_handle_t* handle, uint32_t timeout); + +/** + * @brief Give operation on OS mutex. + * + * @param[in] handle pointer on the mutex handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_mutex_give(OSAL_mutex_handle_t* handle); + +/** + * @brief Disable the OS scheduler context switching. Prevent the OS from scheduling the current thread calling + * #OSAL_disable_context_switching while the OS scheduling is already disable has an undefined behavior. This method may be called + * from an interrupt. + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_disable_context_switching(void); + +/** + * @brief Reenable the OS scheduling that was disabled by #OSAL_disable_context_switching. This method may be called from an + * interrupt. + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_enable_context_switching(void); + +/** + * @brief Asleep the current task during specified number of milliseconds. + * + * @param[in] milliseconds number of milliseconds + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_sleep(uint32_t milliseconds); + +#endif // OSAL_H diff --git a/bsp/projects/microej/util/inc/osal_portmacro.h b/bsp/projects/microej/util/inc/osal_portmacro.h new file mode 100644 index 0000000..5fca326 --- /dev/null +++ b/bsp/projects/microej/util/inc/osal_portmacro.h @@ -0,0 +1,68 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +#ifndef OSAL_PORTMACRO_H +#define OSAL_PORTMACRO_H + +/** + * @file + * @brief OS Abstraction Layer FreeRTOS port macro + * @author MicroEJ Developer Team + * @version 1.1.0 + * @date 6 July 2022 + */ + +#include +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/** @brief Custom OS type definitions */ +#define OSAL_CUSTOM_TYPEDEF + +/** @brief task function entry point */ +typedef TaskFunction_t OSAL_task_entry_point_t; + +/** @brief OS task handle */ +typedef TaskHandle_t OSAL_task_handle_t; + +/** @brief OS queue handle */ +typedef QueueHandle_t OSAL_queue_handle_t; + +/** @brief OS counter semaphore handle */ +typedef SemaphoreHandle_t OSAL_counter_semaphore_handle_t; + +/** @brief OS binary semaphore handle */ +typedef SemaphoreHandle_t OSAL_binary_semaphore_handle_t; + +/** @brief OS mutex handle */ +typedef SemaphoreHandle_t OSAL_mutex_handle_t; + +/** @brief OS task stack */ +typedef int32_t OSAL_task_stack_t; + +/** @brief OS queue */ +typedef int32_t OSAL_queue_t; + +/* + * @brief Declare a task stack. + * + * @param[in] _name name of the variable that defines the stack. + * @param[in] _size size of the stack in bytes. _size must be compile time constant value. + */ +#define OSAL_task_stack_declare(_name, _size) OSAL_task_stack_t _name = _size + +/* + * @brief Declare a queue. + * + * @param[in] _name name of the variable that defines the queue address. + * @param[in] _size number of items that can be stored in the queue. _size must be compile time constant value. + */ +#define OSAL_queue_declare(_name, _size) OSAL_queue_t _name = _size + +#endif // OSAL_PORTMACRO_H diff --git a/bsp/projects/microej/util/microej_util.cmake b/bsp/projects/microej/util/microej_util.cmake new file mode 100644 index 0000000..a9f37bf --- /dev/null +++ b/bsp/projects/microej/util/microej_util.cmake @@ -0,0 +1,15 @@ +# Copyright 2022 MicroEJ Corp. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be found with this software. +# Copyright 2023 NXP +# SPDX-License-Identifier: BSD-3-Clause + +include_guard() +message("microej/util component is included.") + +target_sources(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src/microej_async_worker.c + ${CMAKE_CURRENT_LIST_DIR}/src/microej_pool.c + ${CMAKE_CURRENT_LIST_DIR}/src/osal_FreeRTOS.c +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/inc) diff --git a/bsp/projects/microej/util/src/microej_async_worker.c b/bsp/projects/microej/util/src/microej_async_worker.c new file mode 100644 index 0000000..6f6ee60 --- /dev/null +++ b/bsp/projects/microej/util/src/microej_async_worker.c @@ -0,0 +1,201 @@ +/* + * C + * + * Copyright 2018-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software.. + */ + +/** + * @file + * @brief Asynchronous Worker implementation + * @author MicroEJ Developer Team + * @version 0.4.0 + * @date 17 June 2022 + */ + +#include "microej_async_worker.h" +#include +#include +#include + + +#ifdef __cplusplus + extern "C" { +#endif + +// Entry point of the async worker task. +static void MICROEJ_ASYNC_WORKER_loop(void* args); + +// Generic method for MICROEJ_ASYNC_WORKER_async_exec and MICROEJ_ASYNC_WORKER_async_exec_no_wait +static MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_async_exec_intern(MICROEJ_ASYNC_WORKER_handle_t* async_worker, MICROEJ_ASYNC_WORKER_job_t* job, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done_callback, bool wait); + +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_initialize(MICROEJ_ASYNC_WORKER_handle_t* async_worker, uint8_t* name, OSAL_task_stack_t stack, int32_t priority){ + // Check configuration + int32_t job_count = async_worker->job_count; + if(job_count <= 0 + || async_worker->waiting_threads_length <= 1 // compare with 1 because '+1' is added when declaring the array + ){ + return MICROEJ_ASYNC_WORKER_INVALID_ARGS; + } + + // Init jobs + MICROEJ_ASYNC_WORKER_job_t* jobs = async_worker->free_jobs; + void* params = async_worker->params; + int32_t params_sizeof = async_worker->params_sizeof; + for(int i=0 ; ijobs_queue, async_worker->job_count); + if(res != OSAL_OK){ + return MICROEJ_ASYNC_WORKER_ERROR; + } + + // Create mutex + res = OSAL_mutex_create(name, &async_worker->mutex); + if(res != OSAL_OK){ + return MICROEJ_ASYNC_WORKER_ERROR; + } + + // Create task + res = OSAL_task_create(MICROEJ_ASYNC_WORKER_loop, name, stack, priority, async_worker, &async_worker->task); + if(res != OSAL_OK){ + return MICROEJ_ASYNC_WORKER_ERROR; + } + + return MICROEJ_ASYNC_WORKER_OK; +} + + +MICROEJ_ASYNC_WORKER_job_t* MICROEJ_ASYNC_WORKER_allocate_job(MICROEJ_ASYNC_WORKER_handle_t* async_worker, SNI_callback sni_retry_callback){ + + MICROEJ_ASYNC_WORKER_job_t* job = NULL; + + OSAL_mutex_take(&async_worker->mutex, OSAL_INFINITE_TIME); + { + job = async_worker->free_jobs; + if(job != NULL){ + // Free job found: remove it from the free list + async_worker->free_jobs = job->_intern.next_free_job; + job->_intern.next_free_job = NULL; + } + } + OSAL_mutex_give(&async_worker->mutex); + + if(job == NULL){ + // No free job available: wait for a free job. + // Store the current thread id in the waiting list. + // First check if there is a free element in the waiting list. + int32_t free_waiting_thread_offset = async_worker->free_waiting_thread_offset; + int32_t new_free_waiting_thread_offset = free_waiting_thread_offset + 1; + if(new_free_waiting_thread_offset >= async_worker->waiting_threads_length){ + new_free_waiting_thread_offset = 0; + } + + if(new_free_waiting_thread_offset == async_worker->waiting_thread_offset){ + // The waiting list is full. + SNI_throwNativeIOException(-1, "MICROEJ_ASYNC_WORKER: thread cannot be suspended, waiting list is full."); + } + else { + async_worker->free_waiting_thread_offset = (uint16_t)new_free_waiting_thread_offset; + int32_t thread_id = SNI_getCurrentJavaThreadID(); + async_worker->waiting_threads[free_waiting_thread_offset] = thread_id; + SNI_suspendCurrentJavaThreadWithCallback(0, (SNI_callback) sni_retry_callback, NULL); + } + } + + return job; +} + + +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_free_job(MICROEJ_ASYNC_WORKER_handle_t* async_worker, MICROEJ_ASYNC_WORKER_job_t* job) { + OSAL_mutex_take(&async_worker->mutex, OSAL_INFINITE_TIME); + { + job->_intern.next_free_job = async_worker->free_jobs; + async_worker->free_jobs = job; + + int32_t waiting_thread_offset = async_worker->waiting_thread_offset; + if(waiting_thread_offset != async_worker->free_waiting_thread_offset){ + // A thread was waiting for a free job: notify it + int32_t thread_id = async_worker->waiting_threads[waiting_thread_offset]; + int32_t new_waiting_thread_offset = waiting_thread_offset + 1; + if(new_waiting_thread_offset >= async_worker->waiting_threads_length){ + new_waiting_thread_offset = 0; + } + async_worker->waiting_thread_offset = new_waiting_thread_offset; + SNI_resumeJavaThread(thread_id); + } + } + OSAL_mutex_give(&async_worker->mutex); + + return MICROEJ_ASYNC_WORKER_OK; +} + +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_async_exec(MICROEJ_ASYNC_WORKER_handle_t* async_worker, MICROEJ_ASYNC_WORKER_job_t* job, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done_callback){ + return MICROEJ_ASYNC_WORKER_async_exec_intern(async_worker, job, action, on_done_callback, true); +} + +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_async_exec_no_wait(MICROEJ_ASYNC_WORKER_handle_t* async_worker, MICROEJ_ASYNC_WORKER_job_t* job, MICROEJ_ASYNC_WORKER_action_t action){ + return MICROEJ_ASYNC_WORKER_async_exec_intern(async_worker, job, action, NULL, false); +} + +MICROEJ_ASYNC_WORKER_status_t MICROEJ_ASYNC_WORKER_async_exec_intern(MICROEJ_ASYNC_WORKER_handle_t* async_worker, MICROEJ_ASYNC_WORKER_job_t* job, MICROEJ_ASYNC_WORKER_action_t action, SNI_callback on_done_callback, bool wait){ + job->_intern.action = action; + + if(wait == true){ + job->_intern.thread_id = SNI_getCurrentJavaThreadID(); + } + else { + job->_intern.thread_id = SNI_ERROR; + } + + OSAL_status_t res = OSAL_queue_post(&async_worker->jobs_queue, job); + if(res == OSAL_OK){ + if(wait == true){ + SNI_suspendCurrentJavaThreadWithCallback(0, (SNI_callback)on_done_callback, job); + } + return MICROEJ_ASYNC_WORKER_OK; + } + else { + SNI_throwNativeIOException(-1, "MICROEJ_ASYNC_WORKER: Internal error."); + return MICROEJ_ASYNC_WORKER_ERROR; + } +} + + +MICROEJ_ASYNC_WORKER_job_t* MICROEJ_ASYNC_WORKER_get_job_done(void){ + MICROEJ_ASYNC_WORKER_job_t* job = NULL; + SNI_getCallbackArgs((void**)&job, NULL); + return job; +} + +static void MICROEJ_ASYNC_WORKER_loop(void* args){ + MICROEJ_ASYNC_WORKER_handle_t* async_worker = (MICROEJ_ASYNC_WORKER_handle_t*) args; + + while(1){ + MICROEJ_ASYNC_WORKER_job_t* job; + OSAL_status_t res = OSAL_queue_fetch(&async_worker->jobs_queue, (void**)&job, OSAL_INFINITE_TIME); + + if(res == OSAL_OK){ + // New job to execute + job->_intern.action(job); + if(job->_intern.thread_id != SNI_ERROR){ + SNI_resumeJavaThread(job->_intern.thread_id); + } + else { + MICROEJ_ASYNC_WORKER_free_job(async_worker, job); + } + } + } +} + +#ifdef __cplusplus + } +#endif + + diff --git a/bsp/projects/microej/util/src/microej_pool.c b/bsp/projects/microej/util/src/microej_pool.c new file mode 100644 index 0000000..ae4be8f --- /dev/null +++ b/bsp/projects/microej/util/src/microej_pool.c @@ -0,0 +1,149 @@ +/* + * C + * + * Copyright 2020-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief MicroEJ memory pool implementation + * @author MicroEJ Developer Team + * @version 0.1.0 + */ + +#include "microej_pool.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +POOL_status_t POOL_reserve_f(POOL_ctx_t * _st_pool_ctx, + void ** _ppv_item_reserved) +{ + POOL_status_t e_return; + unsigned int uc_i; + unsigned char uc_found = 0; + + /* test entry function */ + if ((NULL != _ppv_item_reserved) && + (NULL != _st_pool_ctx) && + (NULL != _st_pool_ctx->pv_first_item)) + { + /* looking for a free place in pool */ + for (uc_i = 0;(uc_i < _st_pool_ctx->uc_num_item_in_pool) && (!uc_found);uc_i++) + { + if (POOL_USED != _st_pool_ctx->puc_item_status[uc_i]) + { + uc_found = 1; + _st_pool_ctx->puc_item_status[uc_i] = POOL_USED; + *_ppv_item_reserved = (void*)((unsigned char*)(_st_pool_ctx->pv_first_item) + (uc_i * _st_pool_ctx->ui_size_of_item)); + } + } + + /* test if poll is full */ + if (!uc_found) + { + e_return = POOL_NO_SPACE_AVAILABLE; + } + else + { + e_return = POOL_NO_ERROR; + } + } + else + { + e_return = POOL_ERROR_IN_ENTRY_PARAMETERS; + } + + return (e_return); +} + + +POOL_status_t POOL_get_f(POOL_ctx_t * _st_pool_ctx, void ** _ppv_item_retrieved, + microej_pool_compare_functor_t compare_to, void* characteristic) +{ + POOL_status_t e_return; + unsigned int uc_i; + unsigned char uc_found = 0; + void * _pv_item = NULL; + + /* test entry function */ + if ((NULL != _ppv_item_retrieved) && + (_st_pool_ctx != NULL) && + (NULL != _st_pool_ctx->pv_first_item)) + { + /* looking for the item that matches with the given compare function */ + for (uc_i = 0;(uc_i < _st_pool_ctx->uc_num_item_in_pool) && (!uc_found);uc_i++) + { + _pv_item = (void*)((unsigned char*)(_st_pool_ctx->pv_first_item) + (uc_i * _st_pool_ctx->ui_size_of_item)); + if (POOL_USED == _st_pool_ctx->puc_item_status[uc_i] && compare_to(_pv_item, characteristic)) + { + *_ppv_item_retrieved = _pv_item; + uc_found = 1; + } + } + + /* test if poll is full */ + if (!uc_found) + { + e_return = POOL_ITEM_NOT_FOUND_IN_POOL; + } + else + { + e_return = POOL_NO_ERROR; + } + } + else + { + e_return = POOL_ERROR_IN_ENTRY_PARAMETERS; + } + + return (e_return); +} + +POOL_status_t POOL_free_f(POOL_ctx_t * _st_pool_ctx, + void * const _pv_item_to_free) +{ + POOL_status_t e_return; + unsigned int uc_i; + unsigned char uc_found = 0; + + /* test entry function */ + if ((NULL != _pv_item_to_free) && + (NULL != _st_pool_ctx) && + (NULL != _st_pool_ctx->pv_first_item)) + { + /* looking for item index to free place in pool */ + for (uc_i = 0;(uc_i < _st_pool_ctx->uc_num_item_in_pool) && (!uc_found);uc_i++) + { + if ((void*)((unsigned char*)(_st_pool_ctx->pv_first_item) + (uc_i * _st_pool_ctx->ui_size_of_item)) == _pv_item_to_free) + { + uc_found = 1; + _st_pool_ctx->puc_item_status[uc_i] = POOL_FREE; + } + } + + /* test if item is found */ + if (!uc_found) + { + e_return = POOL_ITEM_NOT_FOUND_IN_POOL; + } + else + { + e_return = POOL_NO_ERROR; + } + } + else + { + e_return = POOL_ERROR_IN_ENTRY_PARAMETERS; + } + + return (e_return); +} + +#ifdef __cplusplus +} +#endif diff --git a/bsp/projects/microej/util/src/osal_FreeRTOS.c b/bsp/projects/microej/util/src/osal_FreeRTOS.c new file mode 100644 index 0000000..693f7d3 --- /dev/null +++ b/bsp/projects/microej/util/src/osal_FreeRTOS.c @@ -0,0 +1,540 @@ +/* + * C + * + * Copyright 2017-2023 MicroEJ Corp. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be found with this software. + */ + +/** + * @file + * @brief OS Abstraction Layer FreeRTOS implementation + * @author MicroEJ Developer Team + * @version 1.1.0 + * @date 6 July 2022 + */ + +#include +#include "osal.h" + +/** + * @brief Convert time from milliseconds to FreeRTOS ticks. + * + * @param[in] time in milliseconds + * + * @return time in FreeRTOS ticks + */ +static TickType_t OSAL_FreeRTOS_convert_time_to_tick(uint32_t milliseconds); + +/** + * @brief Create an OS task and start it. + * + * @param[in] entry_point function called at task startup + * @param[in] name the task name + * @param[in] stack task stack declared using OSAL_task_stack_declare() macro + * @param[in] priority task priority + * @param[in] parameters task entry parameters. NULL if no entry parameters + * @param[in,out] handle pointer on a task handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_task_create(OSAL_task_entry_point_t entry_point, uint8_t* name, OSAL_task_stack_t stack, int32_t priority, void* parameters, OSAL_task_handle_t* handle) +{ + uint16_t stack_size = (uint16_t)stack; + + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xTaskCreate(entry_point, (char const *)name, + (stack_size / (sizeof(portSTACK_TYPE))), + parameters, + (unsigned portBASE_TYPE)priority, + handle) != pdPASS) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Delete an OS task and start it. + * + * @param[in] handle pointer on the task handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_task_delete(OSAL_task_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + vTaskDelete(*handle); + + return OSAL_OK; +} + +/** + * @brief Get the handle of the current OS task. + * + * @param[in,out] handle pointer on a task handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_task_get_current(OSAL_task_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + *handle = (OSAL_task_handle_t)xTaskGetCurrentTaskHandle(); + + return OSAL_OK; +} + +/** + * @brief Create an OS queue with a predefined queue size. + * + * @param[in] name queue name + * @param[in,out] handle pointer on a queue handle + * @param[in] queue structure containing address and size declared using OSAL_queue_declare() macro + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_queue_create(uint8_t* name, OSAL_queue_handle_t* handle, OSAL_queue_t queue) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + *handle = xQueueCreate(queue, sizeof(void *)); + if ((*handle) == NULL) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Delete an OS queue. + * + * @param[in] handle pointer on the queue handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_queue_delete(OSAL_queue_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + vQueueDelete(*handle); + + return OSAL_OK; +} + +/** + * @brief Post a message in an OS queue. + * + * @param[in] handle pointer on the queue handle + * @param[in] msg message to post in the message queue + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_queue_post(OSAL_queue_handle_t* handle, void* msg) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xQueueSend(*handle, &msg, 0) != pdTRUE) + { + return OSAL_NOMEM; + } + + return OSAL_OK; +} + +/** + * @brief Fetch a message from an OS queue. Blocks until a message arrived or a timeout occurred. + * + * @param[in] handle pointer on the queue handle + * @param[in,out] msg message fetched from the OS queue + * @param[in] timeout maximum time to wait for message arrival, OSAL_INFINITE_TIME for infinite timeout + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_queue_fetch(OSAL_queue_handle_t* handle, void** msg, uint32_t timeout) +{ + TickType_t timeout_in_tick = OSAL_FreeRTOS_convert_time_to_tick(timeout); + + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xQueueReceive(*handle, msg, timeout_in_tick) != pdTRUE) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Create an OS counter semaphore with a semaphore count initial value. + * + * @param[in] name counter semaphore name + * @param[in] initial_count counter semaphore initial count value + * @param[in] max_count counter semaphore maximum count value + * @param[in,out] handle pointer on a counter semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_counter_semaphore_create(uint8_t* name, uint32_t initial_count, uint32_t max_count, OSAL_counter_semaphore_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + *handle = xSemaphoreCreateCounting(max_count, initial_count); + if ((*handle) == NULL) + { + return OSAL_NOMEM; + } + + return OSAL_OK; +} + +/** + * @brief Delete an OS counter semaphore. + * + * @param[in] handle pointer on the counter semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_counter_semaphore_delete(OSAL_counter_semaphore_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + vSemaphoreDelete(*handle); + + return OSAL_OK; +} + +/** + * @brief Take operation on OS counter semaphore. Block the current task until counter semaphore + * become available or timeout occurred. Decrease the counter semaphore count value by 1 and + * block the current task if count value equals to 0. + * + * @param[in] handle pointer on the counter semaphore handle + * @param[in] timeout maximum time to wait until the counter semaphore become available, OSAL_INFINITE_TIME for infinite timeout + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_counter_semaphore_take(OSAL_counter_semaphore_handle_t* handle, uint32_t timeout) +{ + TickType_t timeout_in_tick = OSAL_FreeRTOS_convert_time_to_tick(timeout); + + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xSemaphoreTake(*handle, timeout_in_tick) != pdTRUE) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Give operation on OS counter semaphore. Increase the counter semaphore count value by 1 and unblock the current task if count value. + * equals to 0. + * + * @param[in] handle pointer on the counter semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_counter_semaphore_give(OSAL_counter_semaphore_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xSemaphoreGive(*handle) != pdTRUE) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Create an OS binary semaphore with a semaphore count initial value (0 or 1). + * + * @param[in] name counter semaphore name + * @param[in] initial_count counter semaphore initial count value + * @param[in,out] handle pointer on a binary semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_binary_semaphore_create(uint8_t* name, uint32_t initial_count, OSAL_binary_semaphore_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + *handle = xSemaphoreCreateBinary(); + if ((*handle) == NULL) + { + return OSAL_NOMEM; + } + + return OSAL_OK; +} + +/** + * @brief Delete an OS binary semaphore. + * + * @param[in] handle pointer on the binary semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_binary_semaphore_delete(OSAL_binary_semaphore_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + vSemaphoreDelete(*handle); + + return OSAL_OK; +} + +/** + * @brief Take operation on OS binary semaphore. Block the current task until binary semaphore + * become available or timeout occurred. Decrease the binary semaphore count value by 1 and + * block the current task if count value equals to 0. + * + * @param[in] handle pointer on the binary semaphore handle + * @param[in] timeout maximum time to wait until the binary semaphore become available, OSAL_INFINITE_TIME for infinite timeout + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_binary_semaphore_take(OSAL_binary_semaphore_handle_t* handle, uint32_t timeout) +{ + TickType_t timeout_in_tick = OSAL_FreeRTOS_convert_time_to_tick(timeout); + + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xSemaphoreTake(*handle, timeout_in_tick) != pdTRUE) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Give operation on OS binary semaphore. Increase the binary semaphore count value by 1 and unblock the current task if count value. + * equals to 0. + * + * @param[in] handle pointer on the binary semaphore handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_binary_semaphore_give(OSAL_binary_semaphore_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xSemaphoreGive(*handle) != pdTRUE) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Create an OS mutex. + * + * @param[in] name mutex name + * @param[in,out] handle pointer on a mutex handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_mutex_create(uint8_t* name, OSAL_mutex_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + *handle = xSemaphoreCreateMutex(); + if ((*handle) == NULL) + { + return OSAL_NOMEM; + } + + return OSAL_OK; +} + +/** + * @brief Delete an OS mutex. + * + * @param[in] handle pointer on the mutex handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_mutex_delete(OSAL_mutex_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + vSemaphoreDelete(*handle); + + return OSAL_OK; +} + +/** + * @brief Take operation on OS mutex. + * + * @param[in] handle pointer on the mutex handle + * @param[in] timeout maximum time to wait until the mutex become available, OSAL_INFINITE_TIME for infinite timeout + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_mutex_take(OSAL_mutex_handle_t* handle, uint32_t timeout) +{ + TickType_t timeout_in_tick = OSAL_FreeRTOS_convert_time_to_tick(timeout); + + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xSemaphoreTake(*handle, timeout_in_tick) != pdTRUE) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Give operation on OS mutex. + * + * @param[in] handle pointer on the mutex handle + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_mutex_give(OSAL_mutex_handle_t* handle) +{ + if (handle == NULL) + { + return OSAL_WRONG_ARGS; + } + + if (xSemaphoreGive(*handle) != pdTRUE) + { + return OSAL_ERROR; + } + + return OSAL_OK; +} + +/** + * @brief Disable the OS scheduler context switching. Prevent the OS from + * scheduling the current thread calling #OSAL_disable_context_switching while + * the OS scheduling is already disable has an undefined behavior. This method + * may be called from an interrupt. + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_disable_context_switching(void) +{ + vTaskSuspendAll(); + + return OSAL_OK; +} + +/** + * @brief Reenable the OS scheduling that was disabled by #OSAL_disable_context_switching. + * This method may be called from an interrupt. + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_enable_context_switching(void) +{ + xTaskResumeAll(); + + return OSAL_OK; +} + +/** + * @brief Asleep the current task during specified number of milliseconds. + * + * @param[in] milliseconds number of milliseconds + * + * @return operation status (@see OSAL_status_t) + */ +OSAL_status_t OSAL_sleep(uint32_t milliseconds) +{ + TickType_t delay_in_ticks = OSAL_FreeRTOS_convert_time_to_tick(milliseconds); + + vTaskDelay(delay_in_ticks); + + return OSAL_OK; +} + +static TickType_t OSAL_FreeRTOS_convert_time_to_tick(uint32_t milliseconds) +{ + TickType_t time_to_tick_timeout; + + if (milliseconds == OSAL_INFINITE_TIME) + { + time_to_tick_timeout = portMAX_DELAY; + } + else + { + if (milliseconds == 0) + { + time_to_tick_timeout = 0; + } + else + { + time_to_tick_timeout = milliseconds / portTICK_PERIOD_MS; + if (time_to_tick_timeout == 0) + { + time_to_tick_timeout = 1; + } + } + } + + return time_to_tick_timeout; +} diff --git a/bsp/projects/nxpvee-ui/app/main.cpp b/bsp/projects/nxpvee-ui/app/main.cpp new file mode 100644 index 0000000..27c4d3f --- /dev/null +++ b/bsp/projects/nxpvee-ui/app/main.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017, 2024 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* FreeRTOS kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "timers.h" + +/* Freescale includes. */ +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "pin_mux.h" +#include "clock_config.h" +#include "board.h" +#include "LLMJVM.h" +#include "LLBSP_impl.h" +#include "sni.h" + +#include "fsl_clock.h" + +#include "sdcard_helper.h" +#ifdef ENABLE_NET +#include "fsl_phylan8741.h" +#endif + +#ifdef ENABLE_SEC +#include +#include "els_pkc_mbedtls.h" +#endif + +#include "tree_version.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Task priorities. */ +#define nxp_pa_task_PRIORITY (configMAX_PRIORITIES - 6) +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static void nxp_pa_task(void *pvParameters); + +/******************************************************************************* + * Code + ******************************************************************************/ +/*! + * @brief Application entry point. + */ +int main(void) +{ + /* Init board hardware. */ + /* attach FRO 12M to FLEXCOMM4 (debug console) */ + CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1u); + CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH); + + /* attach FRO 12M to FLEXCOMM2 */ + CLOCK_SetClkDiv(kCLOCK_DivFlexcom2Clk, 1u); + CLOCK_AttachClk(kFRO12M_to_FLEXCOMM2); + + CLOCK_SetClkDiv(kCLOCK_DivFlexioClk, 1u); + CLOCK_AttachClk(kPLL0_to_FLEXIO); + BOARD_InitBootClocks(); + BOARD_I2C_ReleaseBus(); + BOARD_InitBootPins(); + BOARD_InitDebugConsole(); + + /* Init smartdma. */ + BOARD_InitSmartDMA(); + +#ifdef ENABLE_NET + /* Init Ethernet clock */ + CLOCK_AttachClk(kNONE_to_ENETRMII); + CLOCK_EnableClock(kCLOCK_Enet); + SYSCON0->PRESETCTRL2 = SYSCON_PRESETCTRL2_ENET_RST_MASK; + SYSCON0->PRESETCTRL2 &= ~SYSCON_PRESETCTRL2_ENET_RST_MASK; +#endif + +#ifdef ENABLE_SEC + /* used in order to initialize the true random number generator TRNG */ + /* The CRYPTO_InitHardware is responsible for initializing various hardware components related to cryptography according to options configured */ + status_t status = CRYPTO_InitHardware() ; + assert( status == kStatus_Success ); +#endif + +#ifdef SD_ENABLED + START_SDCARD_Task(NULL); +#endif + + if (xTaskCreate(nxp_pa_task, "NXP_PA_task", 5*1024, NULL, nxp_pa_task_PRIORITY, NULL) != + pdPASS) + { + PRINTF("Task creation failed!.\r\n"); + while (1) + ; + } + vTaskStartScheduler(); + for (;;) + ; +} + + +void Java_ej_microvg_VectorGraphicsNatives_initialize() { } +void Java_ej_microvg_MatrixNatives_identity() { } + +void microjvm_main(void) { + void* vm; + int32_t err; + int32_t exitcode; + + // create VM + vm = SNI_createVM(); + + if (vm == NULL) { + PRINTF("VM initialization error.\n"); + } else { + PRINTF("VM START\n"); + err = SNI_startVM(vm, 0, NULL); + + if (err < 0) { + // Error occurred + if (err == LLMJVM_E_EVAL_LIMIT) { + PRINTF("Evaluation limits reached.\n"); + } else { + PRINTF("VM execution error (err = %d).\n", -err); + } + } else { + // VM execution ends normally + exitcode = SNI_getExitCode(vm); + PRINTF("VM END (exit code = %d)\n", exitcode); + } + + // delete VM + SNI_destroyVM(vm); + } +} + + +/*! + * @brief Task responsible for printing of "Hello world." message. + */ +extern char _HeapAsFreeRAMSize __asm("_HeapAsFreeRAMSize"); +static void nxp_pa_task(void *pvParameters) +{ + for (;;) + { + PRINTF("\r\nNXP PLATFORM ACCELERATOR\r\n"); + PRINTF("NXP VEE Port '%s' '%s'\r\n", VEE_VERSION, GIT_SHA_1); + PRINTF("NXP VEE Heap size: %u Bytes\r\n", (unsigned)&_HeapAsFreeRAMSize); + + microjvm_main(); + vTaskSuspend(NULL); + } +} +void vApplicationMallocFailedHook() +{ + PRINTF(("\r\nERROR: Malloc failed to allocate memory\r\n")); + + /* Loop forever */ + for (;;) + ; +} + +/*! + * @brief Call the cpuload_idle function in FreeRTOS ilde hook function + */ + +extern "C" void vApplicationIdleHook(void) +{ +} + + +/* Functions used in Core Validation test */ +#include "sni.h" +extern "C" jfloat Java_com_microej_core_tests_MicroejCoreValidation_testFloat (jfloat a, jfloat b) +{ + return a * b; +} + +extern "C" jdouble Java_com_microej_core_tests_MicroejCoreValidation_testDouble (jdouble a, jdouble b) +{ + return a * b; +} + +#ifndef ENABLE_NET +/* need to define this to avoid missing symbol */ +extern "C" int32_t Java_com_is2t_support_net_natives_ChannelNatives_initialize(void) { return 0; } +#endif diff --git a/bsp/projects/nxpvee-ui/app/model_cifarnet_ops_npu.cpp b/bsp/projects/nxpvee-ui/app/model_cifarnet_ops_npu.cpp new file mode 100644 index 0000000..040e276 --- /dev/null +++ b/bsp/projects/nxpvee-ui/app/model_cifarnet_ops_npu.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "tensorflow/lite/micro/kernels/micro_ops.h" +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/kernels/neutron/neutron.h" +#include "fsl_debug_console.h" + +tflite::MicroOpResolver &AI_GetOpsResolver() +{ + static tflite::MicroMutableOpResolver<5> s_microOpResolver; + + s_microOpResolver.AddReshape(); + s_microOpResolver.AddSlice(); + s_microOpResolver.AddSoftmax(); + s_microOpResolver.AddDequantize(); + s_microOpResolver.AddCustom(tflite::GetString_NEUTRON_GRAPH(), + tflite::Register_NEUTRON_GRAPH()); + + return s_microOpResolver; +} diff --git a/bsp/projects/nxpvee-ui/app/tree_version.c.in b/bsp/projects/nxpvee-ui/app/tree_version.c.in new file mode 100644 index 0000000..fdc3528 --- /dev/null +++ b/bsp/projects/nxpvee-ui/app/tree_version.c.in @@ -0,0 +1,9 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +const char * GIT_SHA_1 = "@GIT_SHA_1@"; +const char * VEE_VERSION = "@VEE_VERSION@"; diff --git a/bsp/projects/nxpvee-ui/app/tree_version.h b/bsp/projects/nxpvee-ui/app/tree_version.h new file mode 100644 index 0000000..163b85d --- /dev/null +++ b/bsp/projects/nxpvee-ui/app/tree_version.h @@ -0,0 +1,10 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef TREE_VERSION +#define TREE_VERSION +extern const char * GIT_SHA_1; +extern const char * VEE_VERSION; +#endif diff --git a/bsp/projects/nxpvee-ui/armgcc/CMakeLists.txt b/bsp/projects/nxpvee-ui/armgcc/CMakeLists.txt new file mode 100644 index 0000000..8efd48f --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/CMakeLists.txt @@ -0,0 +1,187 @@ +# CROSS COMPILER SETTING +SET(CMAKE_SYSTEM_NAME Generic) +CMAKE_MINIMUM_REQUIRED (VERSION 3.10.0) + +# THE VERSION NUMBER +SET (MCUXPRESSO_CMAKE_FORMAT_MAJOR_VERSION 2) +SET (MCUXPRESSO_CMAKE_FORMAT_MINOR_VERSION 0) + +include(ide_overrides.cmake OPTIONAL) + +if(CMAKE_SCRIPT_MODE_FILE) + message("${MCUXPRESSO_CMAKE_FORMAT_MAJOR_VERSION}") + return() +endif() + + +# ENABLE ASM +ENABLE_LANGUAGE(ASM) + +SET(CMAKE_STATIC_LIBRARY_PREFIX) +SET(CMAKE_STATIC_LIBRARY_SUFFIX) + +SET(CMAKE_EXECUTABLE_LIBRARY_PREFIX) +SET(CMAKE_EXECUTABLE_LIBRARY_SUFFIX) + +# CURRENT DIRECTORY +SET(ProjDirPath ${CMAKE_CURRENT_SOURCE_DIR}) + +SET(EXECUTABLE_OUTPUT_PATH ${ProjDirPath}/${CMAKE_BUILD_TYPE}) +SET(LIBRARY_OUTPUT_PATH ${ProjDirPath}/${CMAKE_BUILD_TYPE}) + +find_package(Git) + +project(nxpvee_ui) + +file (STRINGS "${ProjDirPath}/../../../nvee_version.txt" VEE_VERSION) + +set(MCUX_BUILD_TYPES debug release) + +set(MCUX_SDK_PROJECT_NAME nxpvee_ui.elf) + +if (NOT DEFINED MicroEjRootDirPath) + SET(MicroEjRootDirPath ${ProjDirPath}/../../microej) +endif() + +if (NOT DEFINED SdkOverlayRootDirPath) + SET(SdkOverlayRootDirPath ${ProjDirPath}/../../../sdk_overlay/) +endif() + +if (NOT DEFINED SdkRootDirPath) + SET(SdkRootDirPath ${ProjDirPath}/../../../mcux-sdk/core) +endif() + +if (NOT DEFINED SdkMiddlewareDirPath) + SET(SdkMiddlewareDirPath ${ProjDirPath}/../../../mcux-sdk/middleware/) +endif() + +if (NOT DEFINED RtosRootDirPath) + SET(RtosRootDirPath ${ProjDirPath}/../../../mcux-sdk/rtos/) +endif() + +set(KERNEL_ELF_NAME ${EXECUTABLE_OUTPUT_PATH}/${MCUX_SDK_PROJECT_NAME} PARENT_SCOPE) +set(KERNEL_BIN_NAME ${EXECUTABLE_OUTPUT_PATH}/nxpvee_ui.bin PARENT_SCOPE) + +if (ENABLE_AI) + set(ADDITIONAL_SRC "${ProjDirPath}/../app/model_cifarnet_ops_npu.cpp") +else() + set(ADDITIONAL_SRC "") +endif(ENABLE_AI) + +include(${ProjDirPath}/flags.cmake) + +include(${ProjDirPath}/config.cmake) + +execute_process(COMMAND + "${GIT_EXECUTABLE}" describe --always --abbrev=8 --dirty + WORKING_DIRECTORY "${ProjDirPath}" + OUTPUT_VARIABLE GIT_SHA_1 + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + +configure_file("${ProjDirPath}/../app/tree_version.c.in" "${CMAKE_CURRENT_BINARY_DIR}/tree_version.c" @ONLY) + +add_executable(${MCUX_SDK_PROJECT_NAME} +"${ProjDirPath}/../config/inc/FreeRTOSConfig.h" +"${ProjDirPath}/../config/inc/lwipopts.h" +"${ProjDirPath}/../bsp/pin_mux.c" +"${ProjDirPath}/../bsp/pin_mux.h" +"${ProjDirPath}/../app/main.cpp" +"${ProjDirPath}/../bsp/board.c" +"${ProjDirPath}/../bsp/board.h" +"${ProjDirPath}/../bsp/clock_config.c" +"${ProjDirPath}/../bsp/clock_config.h" +"${ProjDirPath}/../../common/bsp/sdmmc/ffconf.h" +"${ProjDirPath}/../../common/bsp/sdmmc/sdmmc_config.c" +"${ProjDirPath}/../../common/bsp/sdmmc/sdmmc_config.h" +"${ProjDirPath}/../bsp/display_support.h" +"${ProjDirPath}/../bsp/display_support.c" +"${ProjDirPath}/../bsp/simple_gfx_app_imp.c" +"${CMAKE_CURRENT_BINARY_DIR}/tree_version.c" +"${ADDITIONAL_SRC}" +) + +target_include_directories(${MCUX_SDK_PROJECT_NAME} PRIVATE + ${ProjDirPath}/../bsp + ${ProjDirPath}/../config/inc + ${MicroEjRootDirPath}/ + ${MicroEjRootDirPath}/common/bsp/sdmmc/ + ${MicroEjRootDirPath}/core/inc + ${MicroEjRootDirPath}/ecom-network/inc + ${MicroEjRootDirPath}/fs/inc + ${MicroEjRootDirPath}/net/inc + ${MicroEjRootDirPath}/platform/inc + ${MicroEjRootDirPath}/ui/inc + ${MicroEjRootDirPath}/util/inc + ${SdkMiddlewareDirPath}/mbedtls/include +) + +set_source_files_properties("${ProjDirPath}/../config/inc/FreeRTOSConfig.h" PROPERTIES COMPONENT_CONFIG_FILE "middleware_freertos-kernel_template") +set_source_files_properties("${ProjDirPath}/../../common/bsp/sdmmc/ffconf.h" PROPERTIES COMPONENT_CONFIG_FILE "middleware_fatfs_template_sd") +set_source_files_properties("${ProjDirPath}/../../common/bsp/sdmmc/sdmmc_config.c" PROPERTIES COMPONENT_CONFIG_FILE "middleware_sdmmc_usdhc_template") +set_source_files_properties("${ProjDirPath}/../../common/bsp/sdmmc/sdmmc_config.h" PROPERTIES COMPONENT_CONFIG_FILE "middleware_sdmmc_usdhc_template") + + +if (ENABLE_SEC) +# mbedTLS Config +target_compile_definitions(${MCUX_SDK_PROJECT_NAME} PRIVATE MBEDTLS_CONFIG_FILE="microej_mbedtls_config.h") +endif(ENABLE_SEC) + +set(CMAKE_MODULE_PATH + ${MicroEjRootDirPath}/ai + ${MicroEjRootDirPath}/core + ${MicroEjRootDirPath}/gpio + ${MicroEjRootDirPath}/fs + ${MicroEjRootDirPath}/ecom-network + ${MicroEjRootDirPath}/ecom-network-lwip + ${MicroEjRootDirPath}/net + ${MicroEjRootDirPath}/util + ${MicroEjRootDirPath}/ui + ${MicroEjRootDirPath}/security + ${MicroEjRootDirPath}/ssl + ${ProjDirPath}/../../common/bsp/sdmmc + ${SdkMiddlewareDirPath}/fatfs + ${SdkMiddlewareDirPath}/lwip +) + +include(${SdkRootDirPath}/devices/MCXN947/all_lib_device.cmake) +include(microej_core) +include(microej_fs) +include(microej_util) +include(utility_sdmmc) +include(microej_ui) + +if (ENABLE_SEC) +include(microej_security) +include(microej_ssl) +endif(ENABLE_SEC) + +if (ENABLE_AI) +include(nxpvee_ai) +endif(ENABLE_AI) +include(nxp_gpio) + +if (ENABLE_NET) +include(microej_ecom-network) +include(microej_ecom-network-lwip) +include(microej_net) +endif(ENABLE_NET) + +IF(NOT DEFINED TARGET_LINK_SYSTEM_LIBRARIES) + SET(TARGET_LINK_SYSTEM_LIBRARIES "-lm -lc -lgcc -lnosys") +ENDIF() + +TARGET_LINK_LIBRARIES(${MCUX_SDK_PROJECT_NAME} PRIVATE -Wl,--start-group) + +target_link_libraries(${MCUX_SDK_PROJECT_NAME} PRIVATE ${TARGET_LINK_SYSTEM_LIBRARIES}) + +target_link_libraries(${MCUX_SDK_PROJECT_NAME} PRIVATE ${MicroEjRootDirPath}/platform/lib/microejruntime.a) + +target_link_libraries(${MCUX_SDK_PROJECT_NAME} PRIVATE ${MicroEjRootDirPath}/platform/lib/microejapp.o) + +TARGET_LINK_LIBRARIES(${MCUX_SDK_PROJECT_NAME} PRIVATE -Wl,--end-group) + +ADD_CUSTOM_COMMAND(TARGET ${MCUX_SDK_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_OBJCOPY} +-Obinary ${EXECUTABLE_OUTPUT_PATH}/${MCUX_SDK_PROJECT_NAME} ${EXECUTABLE_OUTPUT_PATH}/nxpvee_ui.bin) + +set_target_properties(${MCUX_SDK_PROJECT_NAME} PROPERTIES ADDITIONAL_CLEAN_FILES "output.map;${EXECUTABLE_OUTPUT_PATH}/nxpvee_ui.bin") + diff --git a/bsp/projects/nxpvee-ui/armgcc/MCXN947_cm33_core0_flash.ld b/bsp/projects/nxpvee-ui/armgcc/MCXN947_cm33_core0_flash.ld new file mode 100644 index 0000000..6db8f4e --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/MCXN947_cm33_core0_flash.ld @@ -0,0 +1,259 @@ +/* +** ################################################################### +** Processors: MCXN947VDF_cm33_core0 +** MCXN947VNL_cm33_core0 +** +** Compiler: GNU C Compiler +** Reference manual: MCXNx4x Reference Manual +** Version: rev. 1.0, 2021-08-03 +** Build: b231116 +** +** Abstract: +** Linker file for the GNU C Compiler +** +** Copyright 2016 Freescale Semiconductor, Inc. +** Copyright 2016-2024 NXP +** SPDX-License-Identifier: BSD-3-Clause +** +** http: www.nxp.com +** mail: support@nxp.com +** +** ################################################################### +*/ + + + +/* Entry Point */ +ENTRY(Reset_Handler) + +HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; +STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0800; +RPMSG_SHMEM_SIZE = DEFINED(__use_shmem__) ? 0x2000 : 0; + +RAM_MAXALIGN = 8; + +TEXT_START = DEFINED(__qspi_xip__) ? 0x80001000 : 0x00000000; /* flexspi boot image start with 0x80000000 */ +TEXT_SIZE = DEFINED(__qspi_xip__) ? 0x0FFFF000 : 0x000C0000; /* flexspi boot image offset at 0x80001000 */ + +/* Specify the memory areas */ +MEMORY +{ + m_interrupts (RX) : ORIGIN = TEXT_START, LENGTH = 0x00000400 + m_text (RX) : ORIGIN = TEXT_START + 0x00000400, LENGTH = TEXT_SIZE - 0x00000400 + m_core1_image (RX) : ORIGIN = 0x000C0000, LENGTH = 0x00040000 + m_data (RW) : ORIGIN = 0x20000000, LENGTH = 0x00068000 - RPMSG_SHMEM_SIZE + rpmsg_sh_mem (RW) : ORIGIN = 0x20068000 - RPMSG_SHMEM_SIZE, LENGTH = RPMSG_SHMEM_SIZE + m_flash1 (RX) : ORIGIN = 0x00100000, LENGTH = 0x00100000 + m_sramx (RW) : ORIGIN = 0x04000000, LENGTH = 0x00018000 + m_flash_config (RX) : ORIGIN = 0x80000400, LENGTH = 0x00000200 + m_usb_sram (RW) : ORIGIN = 0x400BA000, LENGTH = 0x00001000 +} + +/* Define output sections */ +SECTIONS +{ + /* section for storing the secondary core image */ + .core1_code : + { + . = ALIGN(4) ; + KEEP (*(.core1_code)) + *(.core1_code*) + . = ALIGN(4) ; + } > m_core1_image + + /* NOINIT section for rpmsg_sh_mem */ + .noinit_rpmsg_sh_mem (NOLOAD) : ALIGN(4) + { + __RPMSG_SH_MEM_START__ = .; + *(.noinit.$rpmsg_sh_mem*) + . = ALIGN(4) ; + __RPMSG_SH_MEM_END__ = .; + } > rpmsg_sh_mem + + .flash_config : + { + . = ALIGN(4); + __FLASH_BASE = .; + KEEP(* (.flexspi_fcb)) /* FCB section */ + . = ALIGN(4); + } > m_flash_config + + /* The startup code goes first into internal flash */ + .interrupts : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } > m_interrupts + + /* The program code and other data goes into internal flash */ + .text : + { + . = ALIGN(4); + __base_RAM = .; + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + KEEP (*(.init)) + KEEP (*(.fini)) + . = ALIGN(4); + __top_RAM = .; + } > m_text + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > m_text + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } > m_text + + .ctors : + { + __CTOR_LIST__ = .; + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + } > m_text + + .dtors : + { + __DTOR_LIST__ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + } > m_text + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } > m_text + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } > m_text + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } > m_text + + __etext = .; /* define a global symbol at end of code */ + __DATA_ROM = .; /* Symbol is used by startup for data initialization */ + + .data : AT(__DATA_ROM) + { + . = ALIGN(4); + __DATA_RAM = .; + __data_start__ = .; /* create a global symbol at data start */ + *(.ramfunc*) /* for functions in ram */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(NonCacheable.init) /* NonCacheable init section */ + *(NonCacheable) /* NonCacheable section */ + *(CodeQuickAccess) /* quick access code section */ + *(DataQuickAccess) /* quick access data section */ + KEEP(*(.jcr*)) + . = ALIGN(4); + __data_end__ = .; /* define a global symbol at data end */ + } > m_data + + __DATA_END = __DATA_ROM + (__data_end__ - __data_start__); + text_end = ORIGIN(m_text) + LENGTH(m_text); + ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data") + + /* Uninitialized data section */ + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + . = ALIGN(4); + __base_EXTRAM = .; /* create a global symbol at data start */ + __START_BSS = .; + __bss_start__ = .; + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + __END_BSS = .; + __top_EXTRAM = .; /* define a global symbol at data end */ + } > m_data + + .heap : + { + . = ALIGN(8); + __end__ = .; + PROVIDE(end = .); + __HeapBase = .; + . += _HeapAsFreeRAMSize; + __HeapLimit = .; + __heap_limit = .; /* Add for _sbrk */ + } > m_data + + .stack : + { + . = ALIGN(8); + . += STACK_SIZE; + } > m_sramx + + m_usb_bdt (NOLOAD) : + { + . = ALIGN(512); + *(m_usb_bdt) + } > m_usb_sram + + m_usb_global (NOLOAD) : + { + *(m_usb_global) + } > m_usb_sram + + /* Initializes stack on the end of block */ + __StackTop = ORIGIN(m_sramx) + LENGTH(m_sramx) - 1; + __StackLimit = __StackTop - STACK_SIZE; + PROVIDE(__stack = __StackTop); + + /* Define heap size as the total remaining RAM size after all data sections + have been considered. Boot stack is excluded since now moved to m_sramx. + RAM overview : RAM_START -> data -> bss -> heap -> stack -> RAM_END */ + _HeapAsFreeRAMSize = LENGTH(m_data) - (SIZEOF(.data) + SIZEOF(.bss) + RAM_MAXALIGN); + + .ARM.attributes 0 : { *(.ARM.attributes) } + +} + diff --git a/bsp/projects/nxpvee-ui/armgcc/build_all.bat b/bsp/projects/nxpvee-ui/armgcc/build_all.bat new file mode 100644 index 0000000..9910d9c --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/build_all.bat @@ -0,0 +1,25 @@ +SET FLAVOUR=Unix Makefiles +SET CMD=make -j +IF "%~1" == "ninja" ( + SET FLAVOUR=Ninja + SET CMD=ninja +) + +set _all=%* +call set _tail=%%_all:%1 =%% + +if exist CMakeFiles (RD /s /Q CMakeFiles) +if exist Makefile (DEL /s /Q /F Makefile) +if exist cmake_install.cmake (DEL /s /Q /F cmake_install.cmake) +if exist CMakeCache.txt (DEL /s /Q /F CMakeCache.txt) +cmake -DCMAKE_TOOLCHAIN_FILE="../../../mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" -G "%FLAVOUR%" -DCMAKE_BUILD_TYPE=debug %_tail% . +%CMD% + +if exist CMakeFiles (RD /s /Q CMakeFiles) +if exist Makefile (DEL /s /Q /F Makefile) +if exist cmake_install.cmake (DEL /s /Q /F cmake_install.cmake) +if exist CMakeCache.txt (DEL /s /Q /F CMakeCache.txt) +cmake -DCMAKE_TOOLCHAIN_FILE="../../../mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" -G "%FLAVOUR%" -DCMAKE_BUILD_TYPE=release %_tail% . +%CMD% + +IF "%1" == "" ( pause ) diff --git a/bsp/projects/nxpvee-ui/armgcc/build_all.sh b/bsp/projects/nxpvee-ui/armgcc/build_all.sh new file mode 100755 index 0000000..8eb1dba --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/build_all.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +FLAVOUR='Unix Makefiles' +CMD="make -j $(nproc)" + +if [ "${1}" = "ninja" ] +then + FLAVOUR='Ninja' + CMD='ninja' +fi + +if [ -d "CMakeFiles" ];then rm -rf CMakeFiles; fi +if [ -f "Makefile" ];then rm -f Makefile; fi +if [ -f "cmake_install.cmake" ];then rm -f cmake_install.cmake; fi +if [ -f "CMakeCache.txt" ];then rm -f CMakeCache.txt; fi +cmake -DCMAKE_TOOLCHAIN_FILE="../../../mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" -G "${FLAVOUR}" -DCMAKE_BUILD_TYPE=debug "${@:2}" . +${CMD} + +if [ -d "CMakeFiles" ];then rm -rf CMakeFiles; fi +if [ -f "Makefile" ];then rm -f Makefile; fi +if [ -f "cmake_install.cmake" ];then rm -f cmake_install.cmake; fi +if [ -f "CMakeCache.txt" ];then rm -f CMakeCache.txt; fi +cmake -DCMAKE_TOOLCHAIN_FILE="../../../mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" -G "${FLAVOUR}" -DCMAKE_BUILD_TYPE=release "${@:2}" . +${CMD} diff --git a/bsp/projects/nxpvee-ui/armgcc/build_debug.bat b/bsp/projects/nxpvee-ui/armgcc/build_debug.bat new file mode 100644 index 0000000..16db8ec --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/build_debug.bat @@ -0,0 +1,15 @@ +SET FLAVOUR=Unix Makefiles +SET CMD=make -j +IF "%~1" == "ninja" ( + SET FLAVOUR=Ninja + SET CMD=ninja +) +set _all=%* +call set _tail=%%_all:%1 =%% + +if exist CMakeFiles (RD /s /Q CMakeFiles) +if exist Makefile (DEL /s /Q /F Makefile) +if exist cmake_install.cmake (DEL /s /Q /F cmake_install.cmake) +if exist CMakeCache.txt (DEL /s /Q /F CMakeCache.txt) +cmake -DCMAKE_TOOLCHAIN_FILE="../../../mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" -G "%FLAVOUR%" -DCMAKE_BUILD_TYPE=debug %_tail% . +%CMD% 2> build_log.txt diff --git a/bsp/projects/nxpvee-ui/armgcc/build_debug.sh b/bsp/projects/nxpvee-ui/armgcc/build_debug.sh new file mode 100755 index 0000000..45ce747 --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/build_debug.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +FLAVOUR='Unix Makefiles' +CMD="make -j $(nproc)" + +if [ "${1}" = "ninja" ] +then + FLAVOUR='Ninja' + CMD='ninja' +fi + +if [ -d "CMakeFiles" ];then rm -rf CMakeFiles; fi +if [ -f "Makefile" ];then rm -f Makefile; fi +if [ -f "cmake_install.cmake" ];then rm -f cmake_install.cmake; fi +if [ -f "CMakeCache.txt" ];then rm -f CMakeCache.txt; fi +cmake -DCMAKE_TOOLCHAIN_FILE="../../../mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" -G "${FLAVOUR}" -DCMAKE_BUILD_TYPE=debug "${@:2}" . +${CMD} 2>&1 | tee build_log.txt diff --git a/bsp/projects/nxpvee-ui/armgcc/build_release.bat b/bsp/projects/nxpvee-ui/armgcc/build_release.bat new file mode 100644 index 0000000..43ba9cc --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/build_release.bat @@ -0,0 +1,16 @@ +SET FLAVOUR=Unix Makefiles +SET CMD=make -j +IF "%~1" == "ninja" ( + SET FLAVOUR=Ninja + SET CMD=ninja +) + +set _all=%* +call set _tail=%%_all:%1 =%% + +if exist CMakeFiles (RD /s /Q CMakeFiles) +if exist Makefile (DEL /s /Q /F Makefile) +if exist cmake_install.cmake (DEL /s /Q /F cmake_install.cmake) +if exist CMakeCache.txt (DEL /s /Q /F CMakeCache.txt) +cmake -DCMAKE_TOOLCHAIN_FILE="../../../mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" -G "%FLAVOUR%" -DCMAKE_BUILD_TYPE=release %_tail% . +%CMD% 2> build_log.txt diff --git a/bsp/projects/nxpvee-ui/armgcc/build_release.sh b/bsp/projects/nxpvee-ui/armgcc/build_release.sh new file mode 100755 index 0000000..16beea0 --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/build_release.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +FLAVOUR='Unix Makefiles' +CMD="make -j $(nproc)" + +if [ "${1}" = "ninja" ] +then + FLAVOUR='Ninja' + CMD='ninja' +fi + +if [ -d "CMakeFiles" ];then rm -rf CMakeFiles; fi +if [ -f "Makefile" ];then rm -f Makefile; fi +if [ -f "cmake_install.cmake" ];then rm -f cmake_install.cmake; fi +if [ -f "CMakeCache.txt" ];then rm -f CMakeCache.txt; fi +cmake -DCMAKE_TOOLCHAIN_FILE="../../../mcux-sdk/core/tools/cmake_toolchain_files/armgcc.cmake" -G "${FLAVOUR}" -DCMAKE_BUILD_TYPE=release "${@:2}" . +${CMD} 2>&1 | tee build_log.txt diff --git a/bsp/projects/nxpvee-ui/armgcc/clean.bat b/bsp/projects/nxpvee-ui/armgcc/clean.bat new file mode 100644 index 0000000..fa8ce71 --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/clean.bat @@ -0,0 +1,5 @@ +RD /s /Q CMakeFiles +DEL /s /Q /F Makefile cmake_install.cmake CMakeCache.txt +DEL /s /Q /F tree_version.c +IF EXIST debug RD /s /Q debug +IF EXIST release RD /s /Q release diff --git a/bsp/projects/nxpvee-ui/armgcc/clean.sh b/bsp/projects/nxpvee-ui/armgcc/clean.sh new file mode 100755 index 0000000..d999264 --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/clean.sh @@ -0,0 +1,5 @@ +#!/bin/sh +rm -rf CMakeFiles +rm -rf Makefile cmake_install.cmake CMakeCache.txt +rm -rf debug release +rm -rf tree_version.c diff --git a/bsp/projects/nxpvee-ui/armgcc/config.cmake b/bsp/projects/nxpvee-ui/armgcc/config.cmake new file mode 100644 index 0000000..34366ee --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/config.cmake @@ -0,0 +1,146 @@ +# config to select component, the format is CONFIG_USE_${component} +# Please refer to cmake files below to get available components: +# ${SdkRootDirPath}/devices/MCXN947/all_lib_device.cmake + +set(CONFIG_BOARD frdmmcxn947) +set(CONFIG_COMPILER gcc) +set(CONFIG_CORE cm33) +set(CONFIG_CORE_ID cm33_core0) +set(CONFIG_DEVICE_ID MCXN947) +set(CONFIG_DEVICE MCXN947) +set(CONFIG_DSP DSP) +set(CONFIG_FPU SP_FPU) +set(CONFIG_KIT frdmmcxn947) +set(CONFIG_TOOLCHAIN armgcc) +set(CONFIG_USE_CMSIS_Include_core_cm true) +set(CONFIG_USE_COMPONENT_CONFIGURATION false) +set(CONFIG_USE_component_gpio_adapter true) +set(CONFIG_USE_component_lists true) +set(CONFIG_USE_component_lpuart_adapter true) +set(CONFIG_USE_component_osa_free_rtos true) +set(CONFIG_USE_component_osa_interface true) +set(CONFIG_USE_component_serial_manager true) +set(CONFIG_USE_component_serial_manager_uart true) +set(CONFIG_USE_device_MCXN947_CMSIS true) +set(CONFIG_USE_device_MCXN947_startup true) +set(CONFIG_USE_device_MCXN947_system true) +set(CONFIG_USE_driver_clock true) +set(CONFIG_USE_driver_common true) +set(CONFIG_USE_driver_dbi_flexio_edma true) +set(CONFIG_USE_driver_dbi_flexio_smartdma true) +set(CONFIG_USE_driver_dbi true) +set(CONFIG_USE_driver_edma4 true) +set(CONFIG_USE_driver_edma_soc true) +set(CONFIG_USE_driver_flexio_mculcd_edma true) +set(CONFIG_USE_driver_flexio_mculcd_smartdma true) +set(CONFIG_USE_driver_flexio_mculcd true) +set(CONFIG_USE_driver_flexio_spi true) +set(CONFIG_USE_driver_flexio true) +set(CONFIG_USE_driver_ft5406_rt true) +set(CONFIG_USE_driver_gpio true) +set(CONFIG_USE_driver_gt911 true) +set(CONFIG_USE_driver_ili9341 true) +set(CONFIG_USE_driver_inputmux_connections true) +set(CONFIG_USE_driver_inputmux true) +set(CONFIG_USE_driver_lpc_smartdma true) +set(CONFIG_USE_driver_lpflexcomm true) +set(CONFIG_USE_driver_lpi2c true) +set(CONFIG_USE_driver_lpuart true) +set(CONFIG_USE_driver_mcx_spc true) +set(CONFIG_USE_driver_port true) +set(CONFIG_USE_driver_reset true) +set(CONFIG_USE_driver_ssd1963 true) +set(CONFIG_USE_driver_st7796s true) +set(CONFIG_USE_driver_usdhc true) +set(CONFIG_USE_middleware_fatfs_sd true) +set(CONFIG_USE_middleware_fatfs_template_sd true) +set(CONFIG_USE_middleware_fatfs true) +set(CONFIG_USE_middleware_freertos-kernel_cm33_non_trustzone true) +set(CONFIG_USE_middleware_freertos-kernel_extension true) +set(CONFIG_USE_middleware_freertos-kernel_heap_3 true) +set(CONFIG_USE_middleware_freertos-kernel_template true) +set(CONFIG_USE_middleware_freertos-kernel true) +#set(CONFIG_USE_middleware_lvgl_demo_benchmark true) +#set(CONFIG_USE_middleware_lvgl_template true) +#set(CONFIG_USE_middleware_lvgl true) +set(CONFIG_USE_middleware_sdmmc_common true) +set(CONFIG_USE_middleware_sdmmc_host_usdhc_cache true) +set(CONFIG_USE_middleware_sdmmc_host_usdhc_freertos true) +set(CONFIG_USE_middleware_sdmmc_host_usdhc true) +set(CONFIG_USE_middleware_sdmmc_osa_freertos true) +set(CONFIG_USE_middleware_sdmmc_sd true) +set(CONFIG_USE_middleware_sdmmc_usdhc_template true) +set(CONFIG_USE_utilities_misc_utilities true) +set(CONFIG_USE_utility_assert_lite true) +set(CONFIG_USE_utility_assert true) +set(CONFIG_USE_utility_debug_console_lite true) +set(CONFIG_USE_utility_debug_console true) + +if (ENABLE_SEC) +set(CONFIG_USE_component_els_pkc_platform_mcxn true) +set(CONFIG_USE_middleware_mbedtls_port_els_pkc true) +set(CONFIG_USE_middleware_mbedtls true) +set(CONFIG_USE_component_els_pkc true) +set(CONFIG_USE_component_els_pkc_random_modes_ctr true) +set(CONFIG_USE_component_els_pkc_trng_type_els true) +set(CONFIG_USE_component_els_pkc_els true) +set(CONFIG_USE_component_els_pkc_pkc true) +set(CONFIG_USE_component_els_pkc_trng true) +set(CONFIG_USE_component_els_pkc_doc_mcxn true) +set(CONFIG_USE_component_els_pkc_static_lib_mcxn true) +set(CONFIG_USE_component_els_pkc_els_header_only true) +set(CONFIG_USE_component_els_pkc_els_common true) +set(CONFIG_USE_component_els_pkc_standalone_keyManagement true) +set(CONFIG_USE_component_els_pkc_hash true) +set(CONFIG_USE_component_els_pkc_core true) +set(CONFIG_USE_component_els_pkc_session true) +set(CONFIG_USE_component_els_pkc_key true) +set(CONFIG_USE_component_els_pkc_mac_modes true) +set(CONFIG_USE_component_els_pkc_aead_modes true) +set(CONFIG_USE_component_els_pkc_data_integrity true) +set(CONFIG_USE_component_els_pkc_cipher_modes true) +set(CONFIG_USE_component_els_pkc_memory true) +set(CONFIG_USE_component_els_pkc_param_integrity true) +set(CONFIG_USE_component_els_pkc_flow_protection true) +set(CONFIG_USE_component_els_pkc_secure_counter true) +set(CONFIG_USE_component_els_pkc_pre_processor true) +set(CONFIG_USE_component_els_pkc_toolchain true) +set(CONFIG_USE_component_els_pkc_hashmodes true) +set(CONFIG_USE_component_els_pkc_random true) +set(CONFIG_USE_component_els_pkc_random_modes true) +set(CONFIG_USE_component_els_pkc_prng true) +set(CONFIG_USE_component_els_pkc_aes true) +set(CONFIG_USE_component_els_pkc_ecc true) +set(CONFIG_USE_component_els_pkc_math true) +set(CONFIG_USE_component_els_pkc_rsa true) +set(CONFIG_USE_component_els_pkc_mac true) +set(CONFIG_USE_component_els_pkc_padding true) +set(CONFIG_USE_component_els_pkc_hmac true) +set(CONFIG_USE_component_els_pkc_aead true) +set(CONFIG_USE_component_els_pkc_cipher true) +set(CONFIG_USE_middleware_mbedtls_port_els true) +set(CONFIG_USE_middleware_mbedtls_els_pkc_config true) +set(CONFIG_USE_middleware_mbedtls_rt2 true) +endif(ENABLE_SEC) + +if (ENABLE_AI) +set(CONFIG_USE_middleware_eiq_tensorflow_lite_micro_binary true) +set(CONFIG_USE_middleware_eiq_tensorflow_lite_micro_headers true) +set(CONFIG_USE_middleware_eiq_tensorflow_lite_micro_neutron true) +set(CONFIG_USE_middleware_eiq_tensorflow_lite_micro_third_party_flatbuffers true) +set(CONFIG_USE_middleware_eiq_tensorflow_lite_micro_third_party_gemmlowp true) +set(CONFIG_USE_middleware_eiq_tensorflow_lite_micro_third_party_neutron_lib_binary true) +set(CONFIG_USE_middleware_eiq_tensorflow_lite_micro_third_party_ruy true) +endif(ENABLE_AI) + +if (ENABLE_NET) +set(CONFIG_USE_component_silicon_id true) +set(CONFIG_USE_driver_flashiap true) +set(CONFIG_USE_driver_mcx_enet true) +set(CONFIG_USE_driver_phy-common true) +set(CONFIG_USE_driver_phy-device-lan8741 true) +set(CONFIG_USE_middleware_lwip_contrib_ping true) +set(CONFIG_USE_middleware_lwip_mcx_ethernetif true) +set(CONFIG_USE_middleware_lwip_template true) +set(CONFIG_USE_middleware_lwip true) +endif(ENABLE_NET) diff --git a/bsp/projects/nxpvee-ui/armgcc/flags.cmake b/bsp/projects/nxpvee-ui/armgcc/flags.cmake new file mode 100644 index 0000000..c9d6908 --- /dev/null +++ b/bsp/projects/nxpvee-ui/armgcc/flags.cmake @@ -0,0 +1,270 @@ +IF(NOT DEFINED FPU) + SET(FPU "-mfloat-abi=hard -mfpu=fpv5-sp-d16") +ENDIF() + +IF(NOT DEFINED SPECS) + SET(SPECS "--specs=nano.specs --specs=nosys.specs") +ENDIF() + +IF(NOT DEFINED DEBUG_CONSOLE_CONFIG) + SET(DEBUG_CONSOLE_CONFIG "-DSDK_DEBUGCONSOLE=1") +ENDIF() + +IF(ENABLE_AI) + SET(STACK_SZ 0x2000) + SET(HEAP_SZ 0x2F800) + SET(AI_C_FLAG "-DENABLE_AI") +ELSE() + SET(STACK_SZ 0x800) + SET(HEAP_SZ 0x0400) +ENDIF() +IF(ENABLE_NET) + SET(NET_C_FLAG "-DENABLE_NET") +ENDIF() +IF(ENABLE_SEC) + SET(SECURITY_C_FLAG " \ + -DENABLE_SEC \ + -DMBEDTLS_MCUX_ELS_PKC_API \ + -DMBEDTLS_MCUX_USE_PKC \ + -DMBEDTLS_MCUX_ELS_API \ + -DMBEDTLS_MCUX_USE_ELS \ + -DMCUXCL_FEATURE_CSSL_MEMORY_C_FALLBACK \ +") +ENDIF() + +SET(CMAKE_ASM_FLAGS_DEBUG " \ + ${CMAKE_ASM_FLAGS_DEBUG} \ + -DDEBUG \ + -D__STARTUP_CLEAR_BSS \ + -g \ + -mcpu=cortex-m33 \ + -Wall \ + -mthumb \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -ffreestanding \ + -fno-builtin \ + -mapcs \ + -std=gnu99 \ + ${FPU} \ +") +SET(CMAKE_ASM_FLAGS_RELEASE " \ + ${CMAKE_ASM_FLAGS_RELEASE} \ + -DNDEBUG \ + -D__STARTUP_CLEAR_BSS \ + -mcpu=cortex-m33 \ + -Wall \ + -mthumb \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -ffreestanding \ + -fno-builtin \ + -mapcs \ + -std=gnu99 \ + ${FPU} \ +") +SET(CMAKE_C_FLAGS_DEBUG " \ + ${CMAKE_C_FLAGS_DEBUG} \ + -DDEBUG \ + -DCPU_MCXN947VDF_cm33_core0 \ + -DLV_CONF_INCLUDE_SIMPLE=1 \ + -DMCUXPRESSO_SDK \ + -DSDK_I2C_BASED_COMPONENT_USED=1 \ + -DSERIAL_PORT_TYPE_UART=1 \ + -DSDK_OS_FREE_RTOS \ + -DPRINTF_FLOAT_ENABLE=1 \ + -DPRINTF_ADVANCED_ENABLE=1 \ + -DSD_ENABLED \ + -DUSE_RTOS=1 \ + -DDEMO_SDCARD \ + -DTF_LITE_STATIC_MEMORY \ + -DSDK_BOARD_ID=\"MCXN947\" \ + -g \ + -O0 \ + -mcpu=cortex-m33 \ + -DBOARD_LCD_S035=1 \ + -Wall \ + -mthumb \ + -MMD \ + -MP \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -ffreestanding \ + -fno-builtin \ + -mapcs \ + -std=gnu99 \ + ${AI_C_FLAG} \ + ${NET_C_FLAG} \ + ${SECURITY_C_FLAG} \ + ${FPU} \ + ${DEBUG_CONSOLE_CONFIG} \ +") +SET(CMAKE_C_FLAGS_RELEASE " \ + ${CMAKE_C_FLAGS_RELEASE} \ + -DNDEBUG \ + -DCPU_MCXN947VDF_cm33_core0 \ + -DLV_CONF_INCLUDE_SIMPLE=1 \ + -DMCUXPRESSO_SDK \ + -DSDK_I2C_BASED_COMPONENT_USED=1 \ + -DSERIAL_PORT_TYPE_UART=1 \ + -DSDK_OS_FREE_RTOS \ + -DPRINTF_FLOAT_ENABLE=1 \ + -DPRINTF_ADVANCED_ENABLE=1 \ + -DSD_ENABLED \ + -DUSE_RTOS=1 \ + -DDEMO_SDCARD \ + -DTF_LITE_STATIC_MEMORY \ + -DSDK_BOARD_ID=\"MCXN947\" \ + -Os \ + -mcpu=cortex-m33 \ + -DBOARD_LCD_S035=1 \ + -Wall \ + -mthumb \ + -MMD \ + -MP \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -ffreestanding \ + -fno-builtin \ + -mapcs \ + -std=gnu99 \ + ${AI_C_FLAG} \ + ${NET_C_FLAG} \ + ${SECURITY_C_FLAG} \ + ${FPU} \ + ${DEBUG_CONSOLE_CONFIG} \ +") +SET(CMAKE_CXX_FLAGS_DEBUG " \ + ${CMAKE_CXX_FLAGS_DEBUG} \ + -DDEBUG \ + -DCPU_MCXN947VDF_cm33_core0 \ + -DUSE_RTOS=1 \ + -DMCUXPRESSO_SDK \ + -DSERIAL_PORT_TYPE_UART=1 \ + -DPRINTF_FLOAT_ENABLE=1 \ + -DPRINTF_ADVANCED_ENABLE=1 \ + -DSD_ENABLED \ + -DDEMO_SDCARD \ + -DTF_LITE_STATIC_MEMORY \ + -g \ + -O0 \ + -mcpu=cortex-m33 \ + -DBOARD_LCD_S035=1 \ + -Wall \ + -mthumb \ + -MMD \ + -MP \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -ffreestanding \ + -fno-builtin \ + -mapcs \ + -fno-rtti \ + -fno-exceptions \ + ${AI_C_FLAG} \ + ${NET_C_FLAG} \ + ${SECURITY_C_FLAG} \ + ${FPU} \ + ${DEBUG_CONSOLE_CONFIG} \ +") +SET(CMAKE_CXX_FLAGS_RELEASE " \ + ${CMAKE_CXX_FLAGS_RELEASE} \ + -DNDEBUG \ + -DCPU_MCXN947VDF_cm33_core0 \ + -DUSE_RTOS=1 \ + -DMCUXPRESSO_SDK \ + -DSERIAL_PORT_TYPE_UART=1 \ + -DPRINTF_FLOAT_ENABLE=1 \ + -DPRINTF_ADVANCED_ENABLE=1 \ + -DSD_ENABLED \ + -DDEMO_SDCARD \ + -DTF_LITE_STATIC_MEMORY \ + -Os \ + -mcpu=cortex-m33 \ + -DBOARD_LCD_S035=1 \ + -Wall \ + -mthumb \ + -MMD \ + -MP \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -ffreestanding \ + -fno-builtin \ + -mapcs \ + -fno-rtti \ + -fno-exceptions \ + ${AI_C_FLAG} \ + ${NET_C_FLAG} \ + ${SECURITY_C_FLAG} \ + ${FPU} \ + ${DEBUG_CONSOLE_CONFIG} \ +") +SET(CMAKE_EXE_LINKER_FLAGS_DEBUG " \ + ${CMAKE_EXE_LINKER_FLAGS_DEBUG} \ + -g \ + -mcpu=cortex-m33 \ + -Wall \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -ffreestanding \ + -fno-builtin \ + -u _printf_float \ + -mthumb \ + -mapcs \ + -Xlinker \ + --gc-sections \ + -Xlinker \ + -static \ + -Xlinker \ + -z \ + -Xlinker \ + muldefs \ + -Xlinker \ + -Map=output.map \ + -Wl,--print-memory-usage \ + -Xlinker \ + --defsym=__stack_size__=${STACK_SZ} \ + -Xlinker \ + --defsym=__heap_size__=${HEAP_SZ} \ + ${FPU} \ + ${SPECS} \ + -T\"${ProjDirPath}/MCXN947_cm33_core0_flash.ld\" -static \ +") +SET(CMAKE_EXE_LINKER_FLAGS_RELEASE " \ + ${CMAKE_EXE_LINKER_FLAGS_RELEASE} \ + -mcpu=cortex-m33 \ + -Wall \ + -fno-common \ + -ffunction-sections \ + -fdata-sections \ + -ffreestanding \ + -fno-builtin \ + -u _printf_float \ + -mthumb \ + -mapcs \ + -Xlinker \ + --gc-sections \ + -Xlinker \ + -static \ + -Xlinker \ + -z \ + -Xlinker \ + muldefs \ + -Xlinker \ + -Map=output.map \ + -Wl,--print-memory-usage \ + -Xlinker \ + --defsym=__stack_size__=${STACK_SZ} \ + -Xlinker \ + --defsym=__heap_size__=${HEAP_SZ} \ + ${FPU} \ + ${SPECS} \ + -T\"${ProjDirPath}/MCXN947_cm33_core0_flash.ld\" -static \ +") diff --git a/bsp/projects/nxpvee-ui/bsp/board.c b/bsp/projects/nxpvee-ui/bsp/board.c new file mode 100644 index 0000000..a30e7eb --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/board.c @@ -0,0 +1,320 @@ +/* + * Copyright 2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "fsl_common.h" +#include "fsl_debug_console.h" +#include "board.h" +#if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED +#include "fsl_lpi2c.h" +#endif /* SDK_I2C_BASED_COMPONENT_USED */ +#if defined(LPFLEXCOMM_INIT_NOT_USED_IN_DRIVER) && LPFLEXCOMM_INIT_NOT_USED_IN_DRIVER +#include "fsl_lpflexcomm.h" +#endif /* LPFLEXCOMM_INIT_NOT_USED_IN_DRIVER */ +#include "fsl_spc.h" + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +/* Initialize debug console. */ +void BOARD_InitDebugConsole(void) +{ + /* attach 12 MHz clock to FLEXCOMM0 (debug console) */ + CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH); + + RESET_ClearPeripheralReset(BOARD_DEBUG_UART_RST); + + uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ; + +#if defined(LPFLEXCOMM_INIT_NOT_USED_IN_DRIVER) && LPFLEXCOMM_INIT_NOT_USED_IN_DRIVER + LP_FLEXCOMM_Init(BOARD_DEBUG_UART_INSTANCE, LP_FLEXCOMM_PERIPH_LPUART); +#endif /* LPFLEXCOMM_INIT_NOT_USED_IN_DRIVER */ + + DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE, BOARD_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq); +} + +void BOARD_InitDebugConsole_Core1(void) +{ + /* attach 12 MHz clock to FLEXCOMM1 (debug console) */ + // CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH_CORE1); + + RESET_ClearPeripheralReset(BOARD_DEBUG_UART_RST_CORE1); + + uint32_t uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ_CORE1; + + DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE_CORE1, BOARD_DEBUG_UART_BAUDRATE_CORE1, BOARD_DEBUG_UART_TYPE_CORE1, + uartClkSrcFreq); +} + +#if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED +void BOARD_LPI2C_Init(LPI2C_Type *base, uint32_t clkSrc_Hz) +{ + lpi2c_master_config_t lpi2cConfig = {0}; + + /* + * lpi2cConfig.debugEnable = false; + * lpi2cConfig.ignoreAck = false; + * lpi2cConfig.pinConfig = kLPI2C_2PinOpenDrain; + * lpi2cConfig.baudRate_Hz = 100000U; + * lpi2cConfig.busIdleTimeout_ns = 0; + * lpi2cConfig.pinLowTimeout_ns = 0; + * lpi2cConfig.sdaGlitchFilterWidth_ns = 0; + * lpi2cConfig.sclGlitchFilterWidth_ns = 0; + */ + LPI2C_MasterGetDefaultConfig(&lpi2cConfig); + LPI2C_MasterInit(base, &lpi2cConfig, clkSrc_Hz); +} + +status_t BOARD_LPI2C_Send(LPI2C_Type *base, + uint8_t deviceAddress, + uint32_t subAddress, + uint8_t subAddressSize, + uint8_t *txBuff, + uint8_t txBuffSize) +{ + lpi2c_master_transfer_t xfer; + + xfer.flags = kLPI2C_TransferDefaultFlag; + xfer.slaveAddress = deviceAddress; + xfer.direction = kLPI2C_Write; + xfer.subaddress = subAddress; + xfer.subaddressSize = subAddressSize; + xfer.data = txBuff; + xfer.dataSize = txBuffSize; + + return LPI2C_MasterTransferBlocking(base, &xfer); +} + +status_t BOARD_LPI2C_Receive(LPI2C_Type *base, + uint8_t deviceAddress, + uint32_t subAddress, + uint8_t subAddressSize, + uint8_t *rxBuff, + uint8_t rxBuffSize) +{ + lpi2c_master_transfer_t xfer; + + xfer.flags = kLPI2C_TransferDefaultFlag; + xfer.slaveAddress = deviceAddress; + xfer.direction = kLPI2C_Read; + xfer.subaddress = subAddress; + xfer.subaddressSize = subAddressSize; + xfer.data = rxBuff; + xfer.dataSize = rxBuffSize; + + return LPI2C_MasterTransferBlocking(base, &xfer); +} + +status_t BOARD_LPI2C_SendSCCB(LPI2C_Type *base, + uint8_t deviceAddress, + uint32_t subAddress, + uint8_t subAddressSize, + uint8_t *txBuff, + uint8_t txBuffSize) +{ + return BOARD_LPI2C_Send(base, deviceAddress, subAddress, subAddressSize, txBuff, txBuffSize); +} + +status_t BOARD_LPI2C_ReceiveSCCB(LPI2C_Type *base, + uint8_t deviceAddress, + uint32_t subAddress, + uint8_t subAddressSize, + uint8_t *rxBuff, + uint8_t rxBuffSize) +{ + status_t status; + lpi2c_master_transfer_t xfer; + + xfer.flags = kLPI2C_TransferDefaultFlag; + xfer.slaveAddress = deviceAddress; + xfer.direction = kLPI2C_Write; + xfer.subaddress = subAddress; + xfer.subaddressSize = subAddressSize; + xfer.data = NULL; + xfer.dataSize = 0; + + status = LPI2C_MasterTransferBlocking(base, &xfer); + + if (kStatus_Success == status) + { + xfer.subaddressSize = 0; + xfer.direction = kLPI2C_Read; + xfer.data = rxBuff; + xfer.dataSize = rxBuffSize; + + status = LPI2C_MasterTransferBlocking(base, &xfer); + } + + return status; +} + +void BOARD_Accel_I2C_Init(void) +{ + BOARD_LPI2C_Init(BOARD_ACCEL_I2C_BASEADDR, BOARD_ACCEL_I2C_CLOCK_FREQ); +} + +status_t BOARD_Accel_I2C_Send(uint8_t deviceAddress, uint32_t subAddress, uint8_t subaddressSize, uint32_t txBuff) +{ + uint8_t data = (uint8_t)txBuff; + + return BOARD_LPI2C_Send(BOARD_ACCEL_I2C_BASEADDR, deviceAddress, subAddress, subaddressSize, &data, 1); +} + +status_t BOARD_Accel_I2C_Receive( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subaddressSize, uint8_t *rxBuff, uint8_t rxBuffSize) +{ + return BOARD_LPI2C_Receive(BOARD_ACCEL_I2C_BASEADDR, deviceAddress, subAddress, subaddressSize, rxBuff, rxBuffSize); +} + +void BOARD_Codec_I2C_Init(void) +{ + BOARD_LPI2C_Init(BOARD_CODEC_I2C_BASEADDR, BOARD_CODEC_I2C_CLOCK_FREQ); +} + +status_t BOARD_Codec_I2C_Send( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, const uint8_t *txBuff, uint8_t txBuffSize) +{ + return BOARD_LPI2C_Send(BOARD_CODEC_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, (uint8_t *)txBuff, + txBuffSize); +} + +status_t BOARD_Codec_I2C_Receive( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, uint8_t *rxBuff, uint8_t rxBuffSize) +{ + return BOARD_LPI2C_Receive(BOARD_CODEC_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, rxBuff, rxBuffSize); +} + +void BOARD_Camera_I2C_Init(void) +{ + LP_FLEXCOMM_Init(BOARD_CAMERA_I2C_INSTANCE, LP_FLEXCOMM_PERIPH_LPI2C); + BOARD_LPI2C_Init(BOARD_CAMERA_I2C_BASEADDR, BOARD_CAMERA_I2C_CLOCK_FREQ); +} + +status_t BOARD_Camera_I2C_Send( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, const uint8_t *txBuff, uint8_t txBuffSize) +{ + return BOARD_LPI2C_Send(BOARD_CAMERA_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, (uint8_t *)txBuff, + txBuffSize); +} + +status_t BOARD_Camera_I2C_Receive( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, uint8_t *rxBuff, uint8_t rxBuffSize) +{ + return BOARD_LPI2C_Receive(BOARD_CAMERA_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, rxBuff, + rxBuffSize); +} + +status_t BOARD_Camera_I2C_SendSCCB( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, const uint8_t *txBuff, uint8_t txBuffSize) +{ + return BOARD_LPI2C_SendSCCB(BOARD_CAMERA_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, (uint8_t *)txBuff, + txBuffSize); +} + +status_t BOARD_Camera_I2C_ReceiveSCCB( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, uint8_t *rxBuff, uint8_t rxBuffSize) +{ + return BOARD_LPI2C_ReceiveSCCB(BOARD_CAMERA_I2C_BASEADDR, deviceAddress, subAddress, subAddressSize, rxBuff, + rxBuffSize); +} + +#endif /* SDK_I2C_BASED_COMPONENT_USED */ + +/* Update Active mode voltage for OverDrive mode. */ +void BOARD_PowerMode_OD(void) +{ + spc_active_mode_dcdc_option_t opt = { + .DCDCVoltage = kSPC_DCDC_OverdriveVoltage, + .DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength, + }; + SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &opt); + + spc_sram_voltage_config_t cfg = { + .operateVoltage = kSPC_sramOperateAt1P2V, + .requestVoltageUpdate = true, + }; + SPC_SetSRAMOperateVoltage(SPC0, &cfg); +} + +void BOARD_I2C_ReleaseBus(void); + +void BOARD_InitSmartDMA(void) +{ + RESET_ClearPeripheralReset(kMUX_RST_SHIFT_RSTn); + + INPUTMUX_Init(INPUTMUX0); + INPUTMUX_AttachSignal(INPUTMUX0, 0, kINPUTMUX_FlexioToSmartDma); + + /* Turnoff clock to inputmux to save power. Clock is only needed to make changes */ + INPUTMUX_Deinit(INPUTMUX0); + + SMARTDMA_InitWithoutFirmware(); + + NVIC_EnableIRQ(SMARTDMA_IRQn); + NVIC_SetPriority(SMARTDMA_IRQn, 3); +} + +static void i2c_release_bus_delay(void) +{ + SDK_DelayAtLeastUs(100U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); +} + +void BOARD_I2C_ReleaseBus(void) +{ + uint8_t i = 0; + gpio_pin_config_t pin_config; + port_pin_config_t i2c_pin_config = {0}; + + /* Config pin mux as gpio */ + i2c_pin_config.pullSelect = kPORT_PullUp; + i2c_pin_config.mux = kPORT_MuxAsGpio; + + pin_config.pinDirection = kGPIO_DigitalOutput; + pin_config.outputLogic = 1U; + CLOCK_EnableClock(kCLOCK_Port4); + PORT_SetPinConfig(I2C_RELEASE_SCL_PORT, I2C_RELEASE_SCL_PIN, &i2c_pin_config); + PORT_SetPinConfig(I2C_RELEASE_SCL_PORT, I2C_RELEASE_SDA_PIN, &i2c_pin_config); + + GPIO_PinInit(I2C_RELEASE_SCL_GPIO, I2C_RELEASE_SCL_PIN, &pin_config); + GPIO_PinInit(I2C_RELEASE_SDA_GPIO, I2C_RELEASE_SDA_PIN, &pin_config); + + /* Drive SDA low first to simulate a start */ + GPIO_PinWrite(I2C_RELEASE_SDA_GPIO, I2C_RELEASE_SDA_PIN, 0U); + i2c_release_bus_delay(); + + /* Send 9 pulses on SCL and keep SDA high */ + for (i = 0; i < 9; i++) + { + GPIO_PinWrite(I2C_RELEASE_SCL_GPIO, I2C_RELEASE_SCL_PIN, 0U); + i2c_release_bus_delay(); + + GPIO_PinWrite(I2C_RELEASE_SDA_GPIO, I2C_RELEASE_SDA_PIN, 1U); + i2c_release_bus_delay(); + + GPIO_PinWrite(I2C_RELEASE_SCL_GPIO, I2C_RELEASE_SCL_PIN, 1U); + i2c_release_bus_delay(); + i2c_release_bus_delay(); + } + + /* Send stop */ + GPIO_PinWrite(I2C_RELEASE_SCL_GPIO, I2C_RELEASE_SCL_PIN, 0U); + i2c_release_bus_delay(); + + GPIO_PinWrite(I2C_RELEASE_SDA_GPIO, I2C_RELEASE_SDA_PIN, 0U); + i2c_release_bus_delay(); + + GPIO_PinWrite(I2C_RELEASE_SCL_GPIO, I2C_RELEASE_SCL_PIN, 1U); + i2c_release_bus_delay(); + + GPIO_PinWrite(I2C_RELEASE_SDA_GPIO, I2C_RELEASE_SDA_PIN, 1U); + i2c_release_bus_delay(); +} + diff --git a/bsp/projects/nxpvee-ui/bsp/board.h b/bsp/projects/nxpvee-ui/bsp/board.h new file mode 100644 index 0000000..91c0b9b --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/board.h @@ -0,0 +1,280 @@ +/* + * Copyright 2022 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +#include "clock_config.h" +#include "fsl_gpio.h" +#include "fsl_port.h" +#include "fsl_smartdma.h" +#include "fsl_inputmux_connections.h" +#include "fsl_inputmux.h" +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief The board name */ +#define BOARD_NAME "FRDM-MCXN947" + +/*! @brief The UART to use for debug messages. */ +#define BOARD_DEBUG_UART_TYPE kSerialPort_Uart +#define BOARD_DEBUG_UART_BASEADDR (uint32_t) LPUART4 +#define BOARD_DEBUG_UART_INSTANCE 4U +#define BOARD_DEBUG_UART_CLK_FREQ 12000000U +#define BOARD_DEBUG_UART_CLK_ATTACH kFRO12M_to_FLEXCOMM4 +#define BOARD_DEBUG_UART_RST kFC4_RST_SHIFT_RSTn +#define BOARD_DEBUG_UART_CLKSRC kCLOCK_FlexComm4 +#define BOARD_UART_IRQ_HANDLER LP_FLEXCOMM4_IRQHandler +#define BOARD_UART_IRQ LP_FLEXCOMM4_IRQn + +#define BOARD_DEBUG_UART_TYPE_CORE1 kSerialPort_Uart +#define BOARD_DEBUG_UART_BASEADDR_CORE1 (uint32_t) USART1 +#define BOARD_DEBUG_UART_INSTANCE_CORE1 1U +#define BOARD_DEBUG_UART_CLK_FREQ_CORE1 12000000U +#define BOARD_DEBUG_UART_CLK_ATTACH_CORE1 kFRO12M_to_FLEXCOMM1 +#define BOARD_DEBUG_UART_RST_CORE1 kFC1_RST_SHIFT_RSTn +#define BOARD_DEBUG_UART_CLKSRC_CORE1 kCLOCK_Flexcomm1 +#define BOARD_UART_IRQ_HANDLER_CORE1 FLEXCOMM1_IRQHandler +#define BOARD_UART_IRQ_CORE1 FLEXCOMM1_IRQn + +#ifndef BOARD_DEBUG_UART_BAUDRATE +#define BOARD_DEBUG_UART_BAUDRATE 115200U +#endif /* BOARD_DEBUG_UART_BAUDRATE */ + +#ifndef BOARD_DEBUG_UART_BAUDRATE_CORE1 +#define BOARD_DEBUG_UART_BAUDRATE_CORE1 115200U +#endif /* BOARD_DEBUG_UART_BAUDRATE_CORE1 */ + +/*! @brief The UART to use for Bluetooth M.2 interface. */ +#define BOARD_BT_UART_INSTANCE 2 +#define BOARD_BT_UART_BAUDRATE 3000000 +#define BOARD_BT_UART_CLK_FREQ 12000000U +#define BOARD_BT_UART_CLK_ATTACH kFRO12M_to_FLEXCOMM2 + +/*! @brief The ENET PHY address. */ +#define BOARD_ENET0_PHY_ADDRESS (0x00U) /* Phy address of enet port 0. */ + +/*! @brief Memory ranges not usable by the ENET DMA. */ +#ifndef BOARD_ENET_NON_DMA_MEMORY_ARRAY +#define BOARD_ENET_NON_DMA_MEMORY_ARRAY \ + { \ + {0x00000000U, 0x0007FFFFU}, {0x10000000U, 0x17FFFFFFU}, {0x80000000U, 0xDFFFFFFFU}, \ + {0x00000000U, 0x00000000U}, \ + } +#endif /* BOARD_ENET_NON_DMA_MEMORY_ARRAY */ + +#define BOARD_ACCEL_I2C_BASEADDR LPI2C2 +#define BOARD_ACCEL_I2C_CLOCK_FREQ 12000000 + +#define BOARD_CODEC_I2C_BASEADDR LPI2C2 +#define BOARD_CODEC_I2C_CLOCK_FREQ 12000000 +#define BOARD_CODEC_I2C_INSTANCE 2 + +/*! @brief Indexes of the TSI channels for on-board electrodes */ +#ifndef BOARD_TSI_ELECTRODE_1 +#define BOARD_TSI_ELECTRODE_1 3U +#endif + +/*! @brief Indexes of the TSI mutual channels for FRDM-TOUCH board */ +#define BOARD_TSI_MUTUAL_TX_ELECTRODE_1 0U +#define BOARD_TSI_MUTUAL_RX_ELECTRODE_1 14U + +#ifndef BOARD_LED_RED_GPIO +#define BOARD_LED_RED_GPIO GPIO0 +#endif +#ifndef BOARD_LED_RED_GPIO_PIN +#define BOARD_LED_RED_GPIO_PIN 10U +#endif + +#ifndef BOARD_LED_BLUE_GPIO +#define BOARD_LED_BLUE_GPIO GPIO1 +#endif +#ifndef BOARD_LED_BLUE_GPIO_PIN +#define BOARD_LED_BLUE_GPIO_PIN 2U +#endif + +#ifndef BOARD_LED_GREEN_GPIO +#define BOARD_LED_GREEN_GPIO GPIO0 +#endif +#ifndef BOARD_LED_GREEN_GPIO_PIN +#define BOARD_LED_GREEN_GPIO_PIN 27U +#endif + +#ifndef BOARD_SW2_GPIO +#define BOARD_SW2_GPIO GPIO0 +#endif +#ifndef BOARD_SW2_GPIO_PIN +#define BOARD_SW2_GPIO_PIN 23U +#endif +#define BOARD_SW2_NAME "SW2" +#define BOARD_SW2_IRQ GPIO00_IRQn +#define BOARD_SW2_IRQ_HANDLER GPIO00_IRQHandler + +#ifndef BOARD_SW3_GPIO +#define BOARD_SW3_GPIO GPIO0 +#endif +#ifndef BOARD_SW3_GPIO_PIN +#define BOARD_SW3_GPIO_PIN 6U +#endif +#define BOARD_SW3_NAME "SW3" +#define BOARD_SW3_IRQ GPIO00_IRQn +#define BOARD_SW3_IRQ_HANDLER GPIO00_IRQHandler + +/* USB PHY condfiguration */ +#define BOARD_USB_PHY_D_CAL (0x04U) +#define BOARD_USB_PHY_TXCAL45DP (0x07U) +#define BOARD_USB_PHY_TXCAL45DM (0x07U) + +#define BOARD_HAS_NO_CTIMER_OUTPUT_PIN_CONNECTED_TO_LED (1) + +/* Board led color mapping */ +#define LOGIC_LED_ON 0U +#define LOGIC_LED_OFF 1U + +#define LED_RED_INIT(output) \ + GPIO_PinWrite(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, output); \ + BOARD_LED_RED_GPIO->PDDR |= (1U << BOARD_LED_RED_GPIO_PIN) /*!< Enable target LED_RED */ +#define LED_RED_ON() GPIO_PortClear(BOARD_LED_RED_GPIO, 1U << BOARD_LED_RED_GPIO_PIN) /*!< Turn on target LED_RED */ +#define LED_RED_OFF() GPIO_PortSet(BOARD_LED_RED_GPIO, 1U << BOARD_LED_RED_GPIO_PIN) /*!< Turn off target LED_RED */ +#define LED_RED_TOGGLE() GPIO_PortToggle(BOARD_LED_RED_GPIO, 1U << BOARD_LED_RED_GPIO_PIN) /*!< Toggle on target LED_RED */ + +#define LED_BLUE_INIT(output) \ + GPIO_PinWrite(BOARD_LED_BLUE_GPIO, BOARD_LED_BLUE_GPIO_PIN, output); \ + BOARD_LED_BLUE_GPIO->PDDR |= (1U << BOARD_LED_BLUE_GPIO_PIN) /*!< Enable target LED_BLUE */ +#define LED_BLUE_ON() GPIO_PortClear(BOARD_LED_BLUE_GPIO, 1U << BOARD_LED_BLUE_GPIO_PIN) /*!< Turn on target LED_BLUE */ +#define LED_BLUE_OFF() GPIO_PortSet(BOARD_LED_BLUE_GPIO, 1U << BOARD_LED_BLUE_GPIO_PIN) /*!< Turn off target LED_BLUE */ +#define LED_BLUE_TOGGLE() GPIO_PortToggle(BOARD_LED_BLUE_GPIO, 1U << BOARD_LED_BLUE_GPIO_PIN) /*!< Toggle on target LED_BLUE */ + +#define LED_GREEN_INIT(output) \ + GPIO_PinWrite(BOARD_LED_GREEN_GPIO, BOARD_LED_GREEN_GPIO_PIN, output); \ + BOARD_LED_GREEN_GPIO->PDDR |= (1U << BOARD_LED_GREEN_GPIO_PIN) /*!< Enable target LED_GREEN */ +#define LED_GREEN_ON() GPIO_PortClear(BOARD_LED_GREEN_GPIO, 1U << BOARD_LED_GREEN_GPIO_PIN) /*!< Turn on target LED_GREEN */ +#define LED_GREEN_OFF() GPIO_PortSet(BOARD_LED_GREEN_GPIO, 1U << BOARD_LED_GREEN_GPIO_PIN) /*!< Turn off target LED_GREEN */ +#define LED_GREEN_TOGGLE() GPIO_PortToggle(BOARD_LED_GREEN_GPIO, 1U << BOARD_LED_GREEN_GPIO_PIN) /*!< Toggle on target LED_GREEN */ + +/* Display. */ +#define BOARD_LCD_DC_GPIO GPIO0 +#define BOARD_LCD_DC_GPIO_PORT 0U +#define BOARD_LCD_DC_GPIO_PIN 10U + +/* Camera */ +#define BOARD_CAMERA_I2C_BASEADDR LPI2C7 +#define BOARD_CAMERA_I2C_INSTANCE 7 +#define BOARD_CAMERA_I2C_CLOCK_FREQ CLOCK_GetLPFlexCommClkFreq(BOARD_CAMERA_I2C_INSTANCE) + +/* Serial MWM WIFI */ +#define BOARD_SERIAL_MWM_PORT_CLK_FREQ CLOCK_GetFlexCommClkFreq(2) +#define BOARD_SERIAL_MWM_PORT USART2 +#define BOARD_SERIAL_MWM_PORT_IRQn FLEXCOMM2_IRQn +#define BOARD_SERIAL_MWM_RST_WRITE(output) + +/*! @brief The EMVSIM SMARTCARD PHY configuration. */ +#define BOARD_SMARTCARD_MODULE (EMVSIM0) /*!< SMARTCARD communicational module instance */ +#define BOARD_SMARTCARD_MODULE_IRQ (EMVSIM0_IRQn) /*!< SMARTCARD communicational module IRQ handler */ +#define BOARD_SMARTCARD_CLOCK_MODULE_CLK_FREQ (CLOCK_GetEmvsimClkFreq(0U)) +#define BOARD_SMARTCARD_CLOCK_VALUE (4000000U) /*!< SMARTCARD clock frequency */ + +/* ERPC LPSPI configuration */ +#define ERPC_BOARD_LPSPI_SLAVE_READY_USE_GPIO (1) +#define ERPC_BOARD_LPSPI_BASEADDR LPSPI1 +#define ERPC_BOARD_LPSPI_BAUDRATE 500000U +#define ERPC_BOARD_LPSPI_CLKSRC kCLOCK_Flexcomm1 +#define ERPC_BOARD_LPSPI_CLK_FREQ 12000000 // CLOCK_GetFlexCommClkFreq(1) +#define ERPC_BOARD_LPSPI_INT_GPIO GPIO4 +#define ERPC_BOARD_LPSPI_INT_PIN 0U +#define ERPC_BOARD_LPSPI_INT_PIN_IRQ PIN_INT4_IRQn +#define ERPC_BOARD_LPSPI_INT_PIN_IRQ_HANDLER PIN_INT4_IRQHandler + +/* ERPC LPI2C configuration */ +#define ERPC_BOARD_LPI2C_BASEADDR LPI2C2_BASE +#define ERPC_BOARD_LPI2C_BAUDRATE 100000U +#define ERPC_BOARD_LPI2C_CLKSRC kCLOCK_Flexcomm2 +#define ERPC_BOARD_LPI2C_CLK_FREQ 12000000 // CLOCK_GetFlexCommClkFreq(2) +#define ERPC_BOARD_LPI2C_INT_GPIO GPIO0 +#define ERPC_BOARD_LPI2C_INT_PIN 24U +#define ERPC_BOARD_LPI2C_INT_PIN_IRQ PIN_INT0_IRQn +#define ERPC_BOARD_LPI2C_INT_PIN_IRQ_HANDLER PIN_INT0_IRQHandler + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +/******************************************************************************* + * API + ******************************************************************************/ + +void BOARD_InitDebugConsole(void); +void BOARD_InitDebugConsole_Core1(void); +#if defined(SDK_I2C_BASED_COMPONENT_USED) && SDK_I2C_BASED_COMPONENT_USED +void BOARD_LPI2C_Init(LPI2C_Type *base, uint32_t clkSrc_Hz); +status_t BOARD_LPI2C_Send(LPI2C_Type *base, + uint8_t deviceAddress, + uint32_t subAddress, + uint8_t subaddressSize, + uint8_t *txBuff, + uint8_t txBuffSize); +status_t BOARD_LPI2C_Receive(LPI2C_Type *base, + uint8_t deviceAddress, + uint32_t subAddress, + uint8_t subaddressSize, + uint8_t *rxBuff, + uint8_t rxBuffSize); +status_t BOARD_LPI2C_SendSCCB(LPI2C_Type *base, + uint8_t deviceAddress, + uint32_t subAddress, + uint8_t subaddressSize, + uint8_t *txBuff, + uint8_t txBuffSize); +status_t BOARD_LPI2C_ReceiveSCCB(LPI2C_Type *base, + uint8_t deviceAddress, + uint32_t subAddress, + uint8_t subaddressSize, + uint8_t *rxBuff, + uint8_t rxBuffSize); +void BOARD_Accel_I2C_Init(void); +status_t BOARD_Accel_I2C_Send(uint8_t deviceAddress, uint32_t subAddress, uint8_t subaddressSize, uint32_t txBuff); +status_t BOARD_Accel_I2C_Receive( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subaddressSize, uint8_t *rxBuff, uint8_t rxBuffSize); +void BOARD_Codec_I2C_Init(void); +status_t BOARD_Codec_I2C_Send( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, const uint8_t *txBuff, uint8_t txBuffSize); +status_t BOARD_Codec_I2C_Receive( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, uint8_t *rxBuff, uint8_t rxBuffSize); +void BOARD_Camera_I2C_Init(void); +status_t BOARD_Camera_I2C_Send( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, const uint8_t *txBuff, uint8_t txBuffSize); +status_t BOARD_Camera_I2C_Receive( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, uint8_t *rxBuff, uint8_t rxBuffSize); + +status_t BOARD_Camera_I2C_SendSCCB( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, const uint8_t *txBuff, uint8_t txBuffSize); +status_t BOARD_Camera_I2C_ReceiveSCCB( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subAddressSize, uint8_t *rxBuff, uint8_t rxBuffSize); +#endif /* SDK_I2C_BASED_COMPONENT_USED */ + +void BOARD_PowerMode_OD(void); + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define I2C_RELEASE_SDA_PORT PORT4 +#define I2C_RELEASE_SCL_PORT PORT4 +#define I2C_RELEASE_SDA_GPIO GPIO4 +#define I2C_RELEASE_SDA_PIN 0U +#define I2C_RELEASE_SCL_GPIO GPIO4 +#define I2C_RELEASE_SCL_PIN 1U +#define I2C_RELEASE_BUS_COUNT 100U + +void BOARD_I2C_ReleaseBus(void); + +void BOARD_InitSmartDMA(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* _BOARD_H_ */ diff --git a/bsp/projects/nxpvee-ui/bsp/clock_config.c b/bsp/projects/nxpvee-ui/bsp/clock_config.c new file mode 100644 index 0000000..56f23a7 --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/clock_config.c @@ -0,0 +1,451 @@ +/* + * Copyright 2022-2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*********************************************************************************************************************** + * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file + * will be overwritten if the respective MCUXpresso Config Tools is used to update this file. + **********************************************************************************************************************/ +/* + * How to setup clock using clock driver functions: + * + * 1. Setup clock sources. + * + * 2. Set up wait states of the flash. + * + * 3. Set up all dividers. + * + * 4. Set up all selectors to provide selected clocks. + * + */ + +/* clang-format off */ +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!GlobalInfo +product: Clocks v12.0 +processor: MCXN947 +package_id: MCXN947VDF +mcu_data: ksdk2_0 +processor_version: 0.14.14 +board: FRDM-MCXN947 + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ +/* clang-format on */ + +#include "fsl_clock.h" +#include "clock_config.h" +#include "fsl_spc.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +/* System clock frequency. */ +extern uint32_t SystemCoreClock; + +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ +void BOARD_InitBootClocks(void) +{ + BOARD_BootClockPLL150M(); +} + +/******************************************************************************* + ******************** Configuration BOARD_BootClockFRO12M ********************** + ******************************************************************************/ +/* clang-format off */ +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!Configuration +name: BOARD_BootClockFRO12M +outputs: +- {id: CLK_144M_clock.outFreq, value: 144 MHz} +- {id: CLK_48M_clock.outFreq, value: 48 MHz} +- {id: FRO_12M_clock.outFreq, value: 12 MHz} +- {id: MAIN_clock.outFreq, value: 12 MHz} +- {id: Slow_clock.outFreq, value: 3 MHz} +- {id: System_clock.outFreq, value: 12 MHz} +- {id: gdet_clock.outFreq, value: 48 MHz} +- {id: trng_clock.outFreq, value: 48 MHz} +settings: +- {id: SCGMode, value: SIRC} +- {id: SCG.SCSSEL.sel, value: SCG.SIRC} +- {id: SCG_FIRCCSR_FIRCEN_CFG, value: Disabled} +- {id: SYSCON.FREQMEREFCLKSEL.sel, value: SYSCON.evtg_out0a} +- {id: SYSCON.FREQMETARGETCLKSEL.sel, value: SYSCON.evtg_out0a} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ +/* clang-format on */ + +/******************************************************************************* + * Variables for BOARD_BootClockFRO12M configuration + ******************************************************************************/ +/******************************************************************************* + * Code for BOARD_BootClockFRO12M configuration + ******************************************************************************/ +void BOARD_BootClockFRO12M(void) +{ + CLOCK_EnableClock(kCLOCK_Scg); /*!< Enable SCG clock */ + + /* FRO OSC setup - begin, attach FRO12M to MainClock for safety switching */ + CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12M first to ensure we can change the clock setting */ + + /* Set the LDO_CORE VDD regulator to 1.0 V voltage level */ + spc_active_mode_core_ldo_option_t ldoOpt = { + .CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage, + .CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength, + }; + SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOpt); + /* Set the DCDC VDD regulator to 1.0 V voltage level */ + spc_active_mode_dcdc_option_t dcdcOpt = { + .DCDCVoltage = kSPC_DCDC_MidVoltage, + .DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength, + }; + SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &dcdcOpt); + /* Configure Flash wait-states to support 1V voltage level and 12000000Hz frequency */; + FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x0U)); + /* Specifies the 1V operating voltage for the SRAM's read/write timing margin */ + spc_sram_voltage_config_t sramCfg = { + .operateVoltage = kSPC_sramOperateAt1P0V, + .requestVoltageUpdate = true, + }; + SPC_SetSRAMOperateVoltage(SPC0, &sramCfg); + + /*!< Set up clock selectors */ + + /*!< Set up dividers */ + CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U); /*!< Set AHBCLKDIV divider to value 1 */ + + /* Set SystemCoreClock variable */ + SystemCoreClock = BOARD_BOOTCLOCKFRO12M_CORE_CLOCK; +} + +/******************************************************************************* + ******************* Configuration BOARD_BootClockFROHF48M ********************* + ******************************************************************************/ +/* clang-format off */ +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!Configuration +name: BOARD_BootClockFROHF48M +outputs: +- {id: CLK_144M_clock.outFreq, value: 144 MHz} +- {id: CLK_48M_clock.outFreq, value: 48 MHz} +- {id: FRO_12M_clock.outFreq, value: 12 MHz} +- {id: FRO_HF_clock.outFreq, value: 48 MHz} +- {id: MAIN_clock.outFreq, value: 48 MHz} +- {id: Slow_clock.outFreq, value: 12 MHz} +- {id: System_clock.outFreq, value: 48 MHz} +- {id: gdet_clock.outFreq, value: 48 MHz} +- {id: trng_clock.outFreq, value: 48 MHz} +settings: +- {id: SYSCON.FLEXSPICLKSEL.sel, value: NO_CLOCK} +- {id: SYSCON.FREQMEREFCLKSEL.sel, value: SYSCON.evtg_out0a} +- {id: SYSCON.FREQMETARGETCLKSEL.sel, value: SYSCON.evtg_out0a} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ +/* clang-format on */ + +/******************************************************************************* + * Variables for BOARD_BootClockFROHF48M configuration + ******************************************************************************/ +/******************************************************************************* + * Code for BOARD_BootClockFROHF48M configuration + ******************************************************************************/ +void BOARD_BootClockFROHF48M(void) +{ + CLOCK_EnableClock(kCLOCK_Scg); /*!< Enable SCG clock */ + + /* FRO OSC setup - begin, attach FRO12M to MainClock for safety switching */ + CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12M first to ensure we can change the clock setting */ + + /* Set the LDO_CORE VDD regulator to 1.0 V voltage level */ + spc_active_mode_core_ldo_option_t ldoOpt = { + .CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage, + .CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength, + }; + SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOpt); + /* Set the DCDC VDD regulator to 1.0 V voltage level */ + spc_active_mode_dcdc_option_t dcdcOpt = { + .DCDCVoltage = kSPC_DCDC_MidVoltage, + .DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength, + }; + SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &dcdcOpt); + /* Configure Flash wait-states to support 1V voltage level and 48000000Hz frequency */; + FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x1U)); + /* Specifies the 1V operating voltage for the SRAM's read/write timing margin */ + spc_sram_voltage_config_t sramCfg = { + .operateVoltage = kSPC_sramOperateAt1P0V, + .requestVoltageUpdate = true, + }; + SPC_SetSRAMOperateVoltage(SPC0, &sramCfg); + + CLOCK_SetupFROHFClocking(48000000U); /*!< Enable FRO HF(48MHz) output */ + /*!< Set up clock selectors */ + CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); + + /*!< Set up dividers */ + CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U); /*!< Set AHBCLKDIV divider to value 1 */ + + /* Set SystemCoreClock variable */ + SystemCoreClock = BOARD_BOOTCLOCKFROHF48M_CORE_CLOCK; +} + +/******************************************************************************* + ******************* Configuration BOARD_BootClockFROHF144M ******************** + ******************************************************************************/ +/* clang-format off */ +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!Configuration +name: BOARD_BootClockFROHF144M +outputs: +- {id: CLK_144M_clock.outFreq, value: 144 MHz} +- {id: CLK_48M_clock.outFreq, value: 48 MHz} +- {id: FRO_12M_clock.outFreq, value: 12 MHz} +- {id: FRO_HF_clock.outFreq, value: 144 MHz} +- {id: MAIN_clock.outFreq, value: 144 MHz} +- {id: Slow_clock.outFreq, value: 36 MHz} +- {id: System_clock.outFreq, value: 144 MHz} +- {id: gdet_clock.outFreq, value: 48 MHz} +- {id: trng_clock.outFreq, value: 48 MHz} +settings: +- {id: RunPowerMode, value: OD} +- {id: SYSCON.AHBCLKDIV.scale, value: '1', locked: true} +- {id: SYSCON.FLEXSPICLKSEL.sel, value: NO_CLOCK} +- {id: SYSCON.FREQMEREFCLKSEL.sel, value: SYSCON.evtg_out0a} +- {id: SYSCON.FREQMETARGETCLKSEL.sel, value: SYSCON.evtg_out0a} +sources: +- {id: SCG.FIRC.outFreq, value: 144 MHz} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ +/* clang-format on */ + +/******************************************************************************* + * Variables for BOARD_BootClockFROHF144M configuration + ******************************************************************************/ +/******************************************************************************* + * Code for BOARD_BootClockFROHF144M configuration + ******************************************************************************/ +void BOARD_BootClockFROHF144M(void) +{ + CLOCK_EnableClock(kCLOCK_Scg); /*!< Enable SCG clock */ + + /* FRO OSC setup - begin, attach FRO12M to MainClock for safety switching */ + CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12M first to ensure we can change the clock setting */ + + /* Set the DCDC VDD regulator to 1.2 V voltage level */ + spc_active_mode_dcdc_option_t dcdcOpt = { + .DCDCVoltage = kSPC_DCDC_OverdriveVoltage, + .DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength, + }; + SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &dcdcOpt); + /* Set the LDO_CORE VDD regulator to 1.2 V voltage level */ + spc_active_mode_core_ldo_option_t ldoOpt = { + .CoreLDOVoltage = kSPC_CoreLDO_OverDriveVoltage, + .CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength, + }; + SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOpt); + /* Configure Flash wait-states to support 1.2V voltage level and 144000000Hz frequency */; + FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x3U)); + /* Specifies the 1.2V operating voltage for the SRAM's read/write timing margin */ + spc_sram_voltage_config_t sramCfg = { + .operateVoltage = kSPC_sramOperateAt1P2V, + .requestVoltageUpdate = true, + }; + SPC_SetSRAMOperateVoltage(SPC0, &sramCfg); + + CLOCK_SetupFROHFClocking(144000000U); /*!< Enable FRO HF(144MHz) output */ + /*!< Set up clock selectors */ + CLOCK_AttachClk(kFRO_HF_to_MAIN_CLK); + + /*!< Set up dividers */ + CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U); /*!< Set AHBCLKDIV divider to value 1 */ + + /* Set SystemCoreClock variable */ + SystemCoreClock = BOARD_BOOTCLOCKFROHF144M_CORE_CLOCK; +} + +/******************************************************************************* + ******************** Configuration BOARD_BootClockPLL150M ********************* + ******************************************************************************/ +/* clang-format off */ +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!Configuration +name: BOARD_BootClockPLL150M +called_from_default_init: true +outputs: +- {id: CLK_144M_clock.outFreq, value: 144 MHz} +- {id: CLK_48M_clock.outFreq, value: 48 MHz} +- {id: FRO_12M_clock.outFreq, value: 12 MHz} +- {id: FRO_HF_clock.outFreq, value: 48 MHz} +- {id: MAIN_clock.outFreq, value: 150 MHz} +- {id: PLL0_CLK_clock.outFreq, value: 150 MHz} +- {id: Slow_clock.outFreq, value: 37.5 MHz} +- {id: System_clock.outFreq, value: 150 MHz} +- {id: gdet_clock.outFreq, value: 48 MHz} +- {id: trng_clock.outFreq, value: 48 MHz} +settings: +- {id: PLL0_Mode, value: Normal} +- {id: RunPowerMode, value: OD} +- {id: SCGMode, value: PLL0} +- {id: SCG.PLL0M_MULT.scale, value: '50', locked: true} +- {id: SCG.PLL0SRCSEL.sel, value: SCG.FIRC_48M} +- {id: SCG.PLL0_NDIV.scale, value: '8', locked: true} +- {id: SCG.SCSSEL.sel, value: SCG.PLL0_CLK} +- {id: SYSCON.FLEXSPICLKSEL.sel, value: NO_CLOCK} +- {id: SYSCON.FREQMEREFCLKSEL.sel, value: SYSCON.evtg_out0a} +- {id: SYSCON.FREQMETARGETCLKSEL.sel, value: SYSCON.evtg_out0a} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ +/* clang-format on */ + +/******************************************************************************* + * Variables for BOARD_BootClockPLL150M configuration + ******************************************************************************/ +/******************************************************************************* + * Code for BOARD_BootClockPLL150M configuration + ******************************************************************************/ +void BOARD_BootClockPLL150M(void) +{ + CLOCK_EnableClock(kCLOCK_Scg); /*!< Enable SCG clock */ + + /* FRO OSC setup - begin, attach FRO12M to MainClock for safety switching */ + CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12M first to ensure we can change the clock setting */ + + /* Set the DCDC VDD regulator to 1.2 V voltage level */ + spc_active_mode_dcdc_option_t dcdcOpt = { + .DCDCVoltage = kSPC_DCDC_OverdriveVoltage, + .DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength, + }; + SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &dcdcOpt); + /* Set the LDO_CORE VDD regulator to 1.2 V voltage level */ + spc_active_mode_core_ldo_option_t ldoOpt = { + .CoreLDOVoltage = kSPC_CoreLDO_OverDriveVoltage, + .CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength, + }; + SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOpt); + /* Configure Flash wait-states to support 1.2V voltage level and 150000000Hz frequency */; + FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x3U)); + /* Specifies the 1.2V operating voltage for the SRAM's read/write timing margin */ + spc_sram_voltage_config_t sramCfg = { + .operateVoltage = kSPC_sramOperateAt1P2V, + .requestVoltageUpdate = true, + }; + SPC_SetSRAMOperateVoltage(SPC0, &sramCfg); + + CLOCK_SetupFROHFClocking(48000000U); /*!< Enable FRO HF(48MHz) output */ + /*!< Set up PLL0 */ + const pll_setup_t pll0Setup = { + .pllctrl = SCG_APLLCTRL_SOURCE(1U) | SCG_APLLCTRL_SELI(27U) | SCG_APLLCTRL_SELP(13U), + .pllndiv = SCG_APLLNDIV_NDIV(8U), + .pllpdiv = SCG_APLLPDIV_PDIV(1U), + .pllmdiv = SCG_APLLMDIV_MDIV(50U), + .pllRate = 150000000U + }; + CLOCK_SetPLL0Freq(&pll0Setup); /*!< Configure PLL0 to the desired values */ + CLOCK_SetPll0MonitorMode(kSCG_Pll0MonitorDisable); /* Pll0 Monitor is disabled */ + + /*!< Set up clock selectors */ + CLOCK_AttachClk(kPLL0_to_MAIN_CLK); + + /*!< Set up dividers */ + CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U); /*!< Set AHBCLKDIV divider to value 1 */ + + /* Set SystemCoreClock variable */ + SystemCoreClock = BOARD_BOOTCLOCKPLL150M_CORE_CLOCK; +} + +/******************************************************************************* + ******************** Configuration BOARD_BootClockPLL100M ********************* + ******************************************************************************/ +/* clang-format off */ +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!Configuration +name: BOARD_BootClockPLL100M +outputs: +- {id: CLK_144M_clock.outFreq, value: 144 MHz} +- {id: CLK_48M_clock.outFreq, value: 48 MHz} +- {id: CLK_IN_clock.outFreq, value: 24 MHz} +- {id: FRO_12M_clock.outFreq, value: 12 MHz} +- {id: MAIN_clock.outFreq, value: 100 MHz} +- {id: PLL1_CLK_clock.outFreq, value: 100 MHz} +- {id: Slow_clock.outFreq, value: 25 MHz} +- {id: System_clock.outFreq, value: 100 MHz} +- {id: gdet_clock.outFreq, value: 48 MHz} +- {id: trng_clock.outFreq, value: 48 MHz} +settings: +- {id: PLL1_Mode, value: Normal} +- {id: RunPowerMode, value: SD} +- {id: SCGMode, value: PLL1} +- {id: SCG.PLL1M_MULT.scale, value: '100', locked: true} +- {id: SCG.PLL1_NDIV.scale, value: '6', locked: true} +- {id: SCG.PLL1_PDIV.scale, value: '4', locked: true} +- {id: SCG.SCSSEL.sel, value: SCG.PLL1_CLK} +- {id: SCG_FIRCCSR_FIRCEN_CFG, value: Disabled} +- {id: SCG_SOSCCSR_ERFES_SEL, value: CryOsc} +- {id: SCG_SOSCCSR_SOSCEN_CFG, value: Enabled} +- {id: SYSCON.FREQMEREFCLKSEL.sel, value: SYSCON.evtg_out0a} +- {id: SYSCON.FREQMETARGETCLKSEL.sel, value: SYSCON.evtg_out0a} +sources: +- {id: SCG.SOSC.outFreq, value: 24 MHz, enabled: true} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ +/* clang-format on */ + +/******************************************************************************* + * Variables for BOARD_BootClockPLL100M configuration + ******************************************************************************/ +/******************************************************************************* + * Code for BOARD_BootClockPLL100M configuration + ******************************************************************************/ +void BOARD_BootClockPLL100M(void) +{ + CLOCK_EnableClock(kCLOCK_Scg); /*!< Enable SCG clock */ + + /* FRO OSC setup - begin, attach FRO12M to MainClock for safety switching */ + CLOCK_AttachClk(kFRO12M_to_MAIN_CLK); /*!< Switch to FRO 12M first to ensure we can change the clock setting */ + + /* Set the DCDC VDD regulator to 1.1 V voltage level */ + spc_active_mode_dcdc_option_t dcdcOpt = { + .DCDCVoltage = kSPC_DCDC_NormalVoltage, + .DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength, + }; + SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &dcdcOpt); + /* Set the LDO_CORE VDD regulator to 1.1 V voltage level */ + spc_active_mode_core_ldo_option_t ldoOpt = { + .CoreLDOVoltage = kSPC_CoreLDO_NormalVoltage, + .CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength, + }; + SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &ldoOpt); + /* Configure Flash wait-states to support 1.1V voltage level and 100000000Hz frequency */; + FMU0->FCTRL = (FMU0->FCTRL & ~((uint32_t)FMU_FCTRL_RWSC_MASK)) | (FMU_FCTRL_RWSC(0x2U)); + /* Specifies the 1.1V operating voltage for the SRAM's read/write timing margin */ + spc_sram_voltage_config_t sramCfg = { + .operateVoltage = kSPC_sramOperateAt1P1V, + .requestVoltageUpdate = true, + }; + SPC_SetSRAMOperateVoltage(SPC0, &sramCfg); + + CLOCK_SetupExtClocking(24000000U); + CLOCK_SetSysOscMonitorMode(kSCG_SysOscMonitorDisable); /* System OSC Clock Monitor is disabled */ + + /*!< Set up PLL1 */ + const pll_setup_t pll1Setup = { + .pllctrl = SCG_SPLLCTRL_SOURCE(0U) | SCG_SPLLCTRL_SELI(53U) | SCG_SPLLCTRL_SELP(26U), + .pllndiv = SCG_SPLLNDIV_NDIV(6U), + .pllpdiv = SCG_SPLLPDIV_PDIV(2U), + .pllmdiv = SCG_SPLLMDIV_MDIV(100U), + .pllRate = 100000000U + }; + CLOCK_SetPLL1Freq(&pll1Setup); /*!< Configure PLL1 to the desired values */ + CLOCK_SetPll1MonitorMode(kSCG_Pll1MonitorDisable); /* Pll1 Monitor is disabled */ + + /*!< Set up clock selectors */ + CLOCK_AttachClk(kPLL1_to_MAIN_CLK); + + /*!< Set up dividers */ + CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U); /*!< Set AHBCLKDIV divider to value 1 */ + + /* Set SystemCoreClock variable */ + SystemCoreClock = BOARD_BOOTCLOCKPLL100M_CORE_CLOCK; +} + diff --git a/bsp/projects/nxpvee-ui/bsp/clock_config.h b/bsp/projects/nxpvee-ui/bsp/clock_config.h new file mode 100644 index 0000000..67a2ce9 --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/clock_config.h @@ -0,0 +1,177 @@ +/* + * Copyright 2022-2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*********************************************************************************************************************** + * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file + * will be overwritten if the respective MCUXpresso Config Tools is used to update this file. + **********************************************************************************************************************/ + +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ******************** Configuration BOARD_BootClockFRO12M ********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockFRO12M configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKFRO12M_CORE_CLOCK 12000000U /*!< Core clock frequency: 12000000Hz */ +#define BOARD_BOOTCLOCKFRO12M_ROSC_CLOCK 0U /*!< ROSC clock frequency: 0Hz */ + + +/******************************************************************************* + * API for BOARD_BootClockFRO12M configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockFRO12M(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ******************* Configuration BOARD_BootClockFROHF48M ********************* + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockFROHF48M configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKFROHF48M_CORE_CLOCK 48000000U /*!< Core clock frequency: 48000000Hz */ +#define BOARD_BOOTCLOCKFROHF48M_ROSC_CLOCK 0U /*!< ROSC clock frequency: 0Hz */ + + +/******************************************************************************* + * API for BOARD_BootClockFROHF48M configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockFROHF48M(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ******************* Configuration BOARD_BootClockFROHF144M ******************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockFROHF144M configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKFROHF144M_CORE_CLOCK 144000000U /*!< Core clock frequency: 144000000Hz */ +#define BOARD_BOOTCLOCKFROHF144M_ROSC_CLOCK 0U /*!< ROSC clock frequency: 0Hz */ + + +/******************************************************************************* + * API for BOARD_BootClockFROHF144M configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockFROHF144M(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ******************** Configuration BOARD_BootClockPLL150M ********************* + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockPLL150M configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKPLL150M_CORE_CLOCK 150000000U /*!< Core clock frequency: 150000000Hz */ +#define BOARD_BOOTCLOCKPLL150M_ROSC_CLOCK 0U /*!< ROSC clock frequency: 0Hz */ + + +/******************************************************************************* + * API for BOARD_BootClockPLL150M configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockPLL150M(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ******************** Configuration BOARD_BootClockPLL100M ********************* + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockPLL100M configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKPLL100M_CORE_CLOCK 100000000U /*!< Core clock frequency: 100000000Hz */ +#define BOARD_BOOTCLOCKPLL100M_ROSC_CLOCK 0U /*!< ROSC clock frequency: 0Hz */ + + +/******************************************************************************* + * API for BOARD_BootClockPLL100M configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockPLL100M(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ + diff --git a/bsp/projects/nxpvee-ui/bsp/display_support.c b/bsp/projects/nxpvee-ui/bsp/display_support.c new file mode 100644 index 0000000..0a15eeb --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/display_support.c @@ -0,0 +1,629 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "display_support.h" +//#include "lvgl.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "semphr.h" +#endif + +#include "board.h" +#include "fsl_gpio.h" + +#if BOARD_USE_FLEXIO_SMARTDMA +#include "fsl_dbi_flexio_smartdma.h" +#else +#include "fsl_dbi_flexio_edma.h" +#endif +#include "fsl_flexio_mculcd.h" +#include "fsl_lpi2c.h" +#include "fsl_port.h" + +#if BOARD_LCD_S035 +#include "fsl_st7796s.h" +#include "fsl_gt911.h" +#else +#include "fsl_ssd1963.h" +#include "fsl_ft5406_rt.h" +#endif + +#include "fsl_ili9341.h" +#include "fsl_debug_console.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define ILI9341_RAMWR 0x2C + +/* Port Me. Start */ +#if BOARD_LCD_S035 +#else +#define BOARD_SSD1963_XTAL_FREQ 10000000U +#define BOARD_SSD1963_PCLK_FREQ 30000000U +#define BOARD_SSD1963_HSW 48U +#define BOARD_SSD1963_HFP 40U +#define BOARD_SSD1963_HBP 0U +#define BOARD_SSD1963_VSW 3U +#define BOARD_SSD1963_VFP 13U +#define BOARD_SSD1963_VBP 18U +#define BOARD_SSD1963_POLARITY_FLAG 0U +#endif + +/* Macros for FlexIO interfacing the LCD */ +#define BOARD_FLEXIO FLEXIO0 +#define BOARD_FLEXIO_CLOCK_FREQ CLOCK_GetFlexioClkFreq() +#define BOARD_FLEXIO_BAUDRATE_BPS 160000000U + +/* Macros for FlexIO shifter, timer, and pins. */ +#define BOARD_FLEXIO_WR_PIN 1 +#define BOARD_FLEXIO_RD_PIN 0 +#define BOARD_FLEXIO_DATA_PIN_START 16 +#define BOARD_FLEXIO_TX_START_SHIFTER 0 +#define BOARD_FLEXIO_RX_START_SHIFTER 0 +#define BOARD_FLEXIO_TX_END_SHIFTER 7 +#define BOARD_FLEXIO_RX_END_SHIFTER 7 +#define BOARD_FLEXIO_TIMER 0 + +/* Macros for the touch touch controller. */ +#define BOARD_TOUCH_I2C LPI2C2 +#define BOARD_TOUCH_I2C_CLOCK_FREQ CLOCK_GetLPFlexCommClkFreq(2u) +#define BOARD_TOUCH_I2C_BAUDRATE 100000U +/* Port Me. End */ + +#define DEMO_MS_TO_TICK(ms) ((ms * configTICK_RATE_HZ / 1000) + 1) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static void DEMO_InitLcd(void); + +static void DEMO_InitLcdClock(void); + +static status_t DEMO_InitLcdController(void); + +void DEMO_InitTouch(void); + +void DEMO_ReadTouch(int *pressed, int *touch_x, int *touch_y); + +static void DEMO_SetCSPin(bool set); + +static void DEMO_SetRSPin(bool set); + +/******************************************************************************* + * Variables + ******************************************************************************/ +#if BOARD_LCD_S035 +static gt911_handle_t touchHandle; +#else +static ft5406_rt_handle_t touchHandle; +#endif + +#if defined(SDK_OS_FREE_RTOS) +static SemaphoreHandle_t s_memWriteDone; +#else +static volatile bool s_memWriteDone; +#endif + +#if BOARD_LCD_S035 +/* ST7796S LCD controller handle. */ +st7796s_handle_t lcdHandle; +#else +/* SSD1963 LCD controller handle. */ +ssd1963_handle_t lcdHandle; +#endif + +/* DBI XFER handle. */ +#if BOARD_USE_FLEXIO_SMARTDMA +dbi_flexio_smartdma_xfer_handle_t g_dbiFlexioXferHandle; +#else +dbi_flexio_edma_xfer_handle_t g_dbiFlexioXferHandle; +#endif +/* The FlexIO MCU LCD device. */ +FLEXIO_MCULCD_Type flexioLcdDev = { + .flexioBase = BOARD_FLEXIO, + .busType = kFLEXIO_MCULCD_8080, + .dataPinStartIndex = BOARD_FLEXIO_DATA_PIN_START, + .ENWRPinIndex = BOARD_FLEXIO_WR_PIN, + .RDPinIndex = BOARD_FLEXIO_RD_PIN, + .txShifterStartIndex = BOARD_FLEXIO_TX_START_SHIFTER, + .txShifterEndIndex = BOARD_FLEXIO_TX_END_SHIFTER, + .rxShifterStartIndex = BOARD_FLEXIO_RX_START_SHIFTER, + .rxShifterEndIndex = BOARD_FLEXIO_RX_END_SHIFTER, + .timerIndex = BOARD_FLEXIO_TIMER, + .setCSPin = DEMO_SetCSPin, + .setRSPin = DEMO_SetRSPin, + .setRDWRPin = NULL /* Not used in 8080 mode. */ +}; + +SDK_ALIGN(static uint8_t s_frameBuffer[1][LCD_VIRTUAL_BUF_SIZE * LCD_FB_BYTE_PER_PIXEL], 4); + +uint8_t* disp_sup_get_fb_address() { return (uint8_t *)&s_frameBuffer[0]; } + +/******************************************************************************* + * Code + ******************************************************************************/ +static void DEMO_SetCSPin(bool set) +{ + GPIO_PinWrite(BOARD_LCD_CS_GPIO, BOARD_LCD_CS_PIN, (uint8_t)set); +} + +static void DEMO_SetRSPin(bool set) +{ + GPIO_PinWrite(BOARD_LCD_RS_GPIO, BOARD_LCD_RS_PIN, (uint8_t)set); +} + +static void DEMO_DbiMemoryDoneCallback(status_t status, void *userData) +{ +#if defined(SDK_OS_FREE_RTOS) + BaseType_t taskAwake = pdFALSE; + + xSemaphoreGiveFromISR(s_memWriteDone, &taskAwake); + + portYIELD_FROM_ISR(taskAwake); +#else + s_memWriteDone = true; +#endif +} + +#if BOARD_LCD_S035 +void DEMO_LCD_I2C_Init(void) +{ + BOARD_LPI2C_Init(BOARD_TOUCH_I2C, BOARD_TOUCH_I2C_CLOCK_FREQ); +} + +status_t DEMO_LCD_I2C_Send( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subaddressSize, const uint8_t *txBuff, uint8_t txBuffSize) +{ + return BOARD_LPI2C_Send(BOARD_TOUCH_I2C, deviceAddress, subAddress, subaddressSize, (uint8_t *)txBuff, txBuffSize); +} + +status_t DEMO_LCD_I2C_Receive( + uint8_t deviceAddress, uint32_t subAddress, uint8_t subaddressSize, uint8_t *rxBuff, uint8_t rxBuffSize) +{ + return BOARD_LPI2C_Receive(BOARD_TOUCH_I2C, deviceAddress, subAddress, subaddressSize, rxBuff, rxBuffSize); +} + +void DEMO_TouchDelayMs(uint32_t delayMs) +{ +#if defined(SDK_OS_FREE_RTOS) + vTaskDelay(pdMS_TO_TICKS(delayMs)); +#else + SDK_DelayAtLeastUs(delayMs * 1000, CLOCK_GetCoreSysClkFreq()); +#endif +} + +void DEMO_TouchConfigIntPin(gt911_int_pin_mode_t mode) +{ + port_pin_config_t int_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDown, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as GPIO */ + kPORT_MuxAlt0, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + + switch (mode) + { + case kGT911_IntPinPullUp: + int_config.pullSelect = kPORT_PullUp; + break; + case kGT911_IntPinPullDown: + int_config.pullSelect = kPORT_PullDown; + break; + case kGT911_IntPinInput: + int_config.pullSelect = kPORT_PullDisable; + break; + default: + break; + }; + + PORT_SetPinConfig(BOARD_LCD_INT_PORT, BOARD_LCD_INT_PIN, &int_config); +} + +void DEMO_TouchConfigResetPin(bool pullUp) +{ + /* + * As touch controller and display controller shares the same reset pin, + * we do not do actual reset / address configuration here. Please check below for + * the relationship between RST pin and INT pin. + * + */ +} +#endif + +/* Clear the LCD controller video memory content. */ +static void DEMO_ClearLcd(void) +{ + int32_t leftLinesToClear = LCD_HEIGHT; + int32_t curLinesToClear; + int32_t startLine = 0; + + while (leftLinesToClear > 0) + { + curLinesToClear = + (leftLinesToClear > (2 * LCD_VIRTUAL_BUF_HEIGHT)) ? (2 * LCD_VIRTUAL_BUF_HEIGHT) : leftLinesToClear; + +#if BOARD_LCD_S035 + ST7796S_SelectArea(&lcdHandle, 0, startLine, LCD_WIDTH - 1, startLine + curLinesToClear - 1); +#else + SSD1963_SelectArea(&lcdHandle, 0, startLine, LCD_WIDTH - 1, startLine + curLinesToClear - 1); +#endif + +#if !defined(SDK_OS_FREE_RTOS) + s_memWriteDone = false; +#endif + +#if BOARD_LCD_S035 + ST7796S_WritePixels(&lcdHandle, (uint16_t *)s_frameBuffer, curLinesToClear * LCD_WIDTH); +#else + SSD1963_WriteMemory(&lcdHandle, (const uint8_t *)s_frameBuffer, + curLinesToClear * LCD_WIDTH * LCD_FB_BYTE_PER_PIXEL); +#endif + +#if defined(SDK_OS_FREE_RTOS) + if (xSemaphoreTake(s_memWriteDone, portMAX_DELAY) != pdTRUE) + { + PRINTF("Wait semaphore error: s_memWriteDone\r\n"); + assert(0); + } +#else + while (false == s_memWriteDone) + { + } +#endif + + startLine += curLinesToClear; + leftLinesToClear -= curLinesToClear; + } +} + +status_t DEMO_InitLcdController(void) +{ + status_t status; + + flexio_mculcd_config_t flexioMcuLcdConfig; + +#if BOARD_LCD_S035 + const st7796s_config_t st7796sConfig = {.driverPreset = kST7796S_DriverPresetLCDPARS035, + .pixelFormat = kST7796S_PixelFormatRGB565, + .orientationMode = kST7796S_Orientation270, + .teConfig = kST7796S_TEDisabled, + .invertDisplay = true, + .flipDisplay = true, + .bgrFilter = true}; +#else + const ssd1963_config_t ssd1963Config = {.pclkFreq_Hz = BOARD_SSD1963_PCLK_FREQ, + .pixelInterface = kSSD1963_RGB565, + .panelDataWidth = kSSD1963_PanelData24Bit, + .polarityFlags = BOARD_SSD1963_POLARITY_FLAG, + .panelWidth = LCD_WIDTH, + .panelHeight = LCD_HEIGHT, + .hsw = BOARD_SSD1963_HSW, + .hfp = BOARD_SSD1963_HFP, + .hbp = BOARD_SSD1963_HBP, + .vsw = BOARD_SSD1963_VSW, + .vfp = BOARD_SSD1963_VFP, + .vbp = BOARD_SSD1963_VBP}; +#endif + + const gpio_pin_config_t pinConfig = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 1, + }; + +#if BOARD_USE_FLEXIO_SMARTDMA + flexio_mculcd_smartdma_config_t flexioEzhConfig = { + .inputPixelFormat = kFLEXIO_MCULCD_RGB565, + .outputPixelFormat = kFLEXIO_MCULCD_RGB565, + }; +#endif + + /* Set SSD1963 CS, RS, and reset pin to output. */ + GPIO_PinInit(BOARD_LCD_RST_GPIO, BOARD_LCD_RST_PIN, &pinConfig); + GPIO_PinInit(BOARD_LCD_CS_GPIO, BOARD_LCD_CS_PIN, &pinConfig); + GPIO_PinInit(BOARD_LCD_RS_GPIO, BOARD_LCD_RS_PIN, &pinConfig); + + /* Initialize the flexio MCU LCD. */ + /* + * flexioMcuLcdConfig.enable = true; + * flexioMcuLcdConfig.enableInDoze = false; + * flexioMcuLcdConfig.enableInDebug = true; + * flexioMcuLcdConfig.enableFastAccess = true; + * flexioMcuLcdConfig.baudRate_Bps = 96000000U; + */ + FLEXIO_MCULCD_GetDefaultConfig(&flexioMcuLcdConfig); + flexioMcuLcdConfig.baudRate_Bps = BOARD_FLEXIO_BAUDRATE_BPS; + + status = FLEXIO_MCULCD_Init(&flexioLcdDev, &flexioMcuLcdConfig, BOARD_FLEXIO_CLOCK_FREQ); + + if (kStatus_Success != status) + { + return status; + } + +#if BOARD_USE_FLEXIO_SMARTDMA + /* Create the DBI XFER handle. */ + status = DBI_FLEXIO_SMARTDMA_CreateXferHandle(&g_dbiFlexioXferHandle, &flexioLcdDev, &flexioEzhConfig); +#else + /* Create the DBI XFER handle. Because DMA transfer is not used, so don't + * need to create DMA handle. + */ + status = DBI_FLEXIO_EDMA_CreateXferHandle(&g_dbiFlexioXferHandle, &flexioLcdDev, NULL, NULL); +#endif + + if (kStatus_Success != status) + { + return status; + } + + /* Reset the SSD1963 LCD controller. */ + GPIO_PinWrite(BOARD_LCD_RST_GPIO, BOARD_LCD_RST_PIN, 0); + +#if BOARD_LCD_S035 + /* Required for GT911 I2C address mode 0 */ + DEMO_TouchConfigIntPin(kGT911_IntPinPullDown); +#endif + +#if defined(SDK_OS_FREE_RTOS) + vTaskDelay(DEMO_MS_TO_TICK(1)); /* Delay at least 10ns. */ +#else + SDK_DelayAtLeastUs(1000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); +#endif + GPIO_PinWrite(BOARD_LCD_RST_GPIO, BOARD_LCD_RST_PIN, 1); + +#if BOARD_LCD_S035 + DEMO_TouchConfigIntPin(kGT911_IntPinInput); +#endif + +#if defined(SDK_OS_FREE_RTOS) + vTaskDelay(DEMO_MS_TO_TICK(5)); /* Delay at 5ms. */ +#else + SDK_DelayAtLeastUs(5000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); +#endif + +#if BOARD_USE_FLEXIO_SMARTDMA +#if BOARD_LCD_S035 + status = ST7796S_Init(&lcdHandle, &st7796sConfig, &g_dbiFlexioSmartdmaXferOps, &g_dbiFlexioXferHandle); +#else + status = SSD1963_Init(&lcdHandle, &ssd1963Config, &g_dbiFlexioSmartdmaXferOps, &g_dbiFlexioXferHandle, + BOARD_SSD1963_XTAL_FREQ); +#endif +#else +#if BOARD_LCD_S035 + status = ST7796S_Init(&lcdHandle, &st7796sConfig, &g_dbiFlexioEdmaXferOps, &g_dbiFlexioXferHandle); +#else + status = SSD1963_Init(&lcdHandle, &ssd1963Config, &g_dbiFlexioEdmaXferOps, &g_dbiFlexioXferHandle, + BOARD_SSD1963_XTAL_FREQ); +#endif +#endif + + if (status == kStatus_Success) + { +#if BOARD_LCD_S035 + ST7796S_SetMemoryDoneCallback(&lcdHandle, DEMO_DbiMemoryDoneCallback, NULL); +#else + SSD1963_SetMemoryDoneCallback(&lcdHandle, DEMO_DbiMemoryDoneCallback, NULL); +#endif + + /* Clear the SSD1963 video ram. */ + DEMO_ClearLcd(); + +#if BOARD_LCD_S035 + ST7796S_EnableDisplay(&lcdHandle, true); +#else + SSD1963_StartDisplay(&lcdHandle); + + SSD1963_SetBackLight(&lcdHandle, 128); +#endif + } + else + { + PRINTF("LCD controller initialization failed.\r\n"); + } + + PRINTF("LCD controller initialization OK.\r\n"); + return status; +} + +static void DEMO_InitLcdClock(void) +{ +} + +static void DEMO_InitLcd(void) +{ +#if defined(SDK_OS_FREE_RTOS) + PRINTF("DEMO_InitLcd sem create\r\n"); + s_memWriteDone = xSemaphoreCreateBinary(); + if (NULL == s_memWriteDone) + { + PRINTF("Frame semaphore create failed\r\n"); + assert(0); + } +#else + s_memWriteDone = false; +#endif + + DEMO_InitLcdClock(); + DEMO_InitLcdController(); +} + +void disp_sup_flush(uint8_t* srcAddr, uint32_t startX, uint32_t startY, + uint32_t endX, uint32_t endY, uint32_t number_pixel) +{ + +#if BOARD_LCD_S035 + uint32_t flush_width = endX - startX + 1; + if(flush_width == LCD_WIDTH) + { + ST7796S_SelectArea(&lcdHandle, startX, startY, endX, endY); + ST7796S_WritePixels(&lcdHandle, (uint16_t *)srcAddr, number_pixel); + if (xSemaphoreTake(s_memWriteDone, portMAX_DELAY) != pdTRUE) + { + PRINTF("Wait semaphore error: s_memWriteDone\r\n"); + assert(0); + } + } + else + { + uint32_t flush_height = endY - startY + 1; + for(int i = 0; i < flush_height; i++) + { + ST7796S_SelectArea(&lcdHandle, startX, startY + i, endX, endY + i + 1); + ST7796S_WritePixels(&lcdHandle, (uint16_t *)srcAddr + i * LCD_WIDTH, flush_width); + if (xSemaphoreTake(s_memWriteDone, portMAX_DELAY) != pdTRUE) + { + PRINTF("Wait semaphore error: s_memWriteDone\r\n"); + assert(0); + } + } + } +#endif +} + +void disp_sup_pre_init(void) +{ +} + +void disp_sup_disp_init(void) +{ + memset(s_frameBuffer, 0, sizeof(s_frameBuffer)); + + /*------------------------- + * Initialize your display + * -----------------------*/ + DEMO_InitLcd(); +} + +void disp_sup_indev_init(void) +{ +} + +/*Initialize your touchpad*/ +void DEMO_InitTouch(void) +{ +#if BOARD_LCD_S035 + DEMO_LCD_I2C_Init(); + + gt911_config_t touchConfig = {.I2C_SendFunc = DEMO_LCD_I2C_Send, + .I2C_ReceiveFunc = DEMO_LCD_I2C_Receive, + .timeDelayMsFunc = DEMO_TouchDelayMs, + .intPinFunc = DEMO_TouchConfigIntPin, + .pullResetPinFunc = DEMO_TouchConfigResetPin, + .touchPointNum = 5, + .i2cAddrMode = kGT911_I2cAddrMode0, + .intTrigMode = kGT911_IntFallingEdge}; + + GT911_Init(&touchHandle, &touchConfig); +#else + lpi2c_master_config_t masterConfig; + + /* + * masterConfig.enableMaster = true; + * masterConfig.baudRate_Bps = 100000U; + * masterConfig.enableTimeout = false; + */ + LPI2C_MasterGetDefaultConfig(&masterConfig); + + /* Change the default baudrate configuration */ + masterConfig.baudRate_Hz = BOARD_TOUCH_I2C_BAUDRATE; + + /* Initialize the I2C master peripheral */ + LPI2C_MasterInit(BOARD_TOUCH_I2C, &masterConfig, BOARD_TOUCH_I2C_CLOCK_FREQ); + + /* Initialize the touch handle. */ + FT5406_RT_Init(&touchHandle, BOARD_TOUCH_I2C); +#endif +} + +/* Will be called by the library to read the touchpad */ +void DEMO_ReadTouch(int *pressed, int *touch_x, int *touch_y) +{ +#if BOARD_LCD_S035 + touch_point_t tp[5]; + + uint8_t tp_count = 5; + GT911_GetMultiTouch(&touchHandle, &tp_count, tp); + + /** + * GT911 supports 5 points tracking, we only tracks ID #0. + * + */ + + static bool found_track = false; + + for (uint8_t i = 0; i < tp_count; i++) + { + /* Found track ID #0 */ + if (tp[i].touchID == 0) + { + *pressed = 0; + switch (lcdHandle.orientationMode) + { + case kST7796S_Orientation0: + *touch_x = tp[i].x; + *touch_y = tp[i].y; + break; + case kST7796S_Orientation90: + *touch_x = touchHandle.resolutionY - tp[i].y; + *touch_y = tp[i].x; + break; + case kST7796S_Orientation180: + *touch_x = tp[i].x; + *touch_y = tp[i].y; + break; + case kST7796S_Orientation270: + *touch_x = tp[i].y; + *touch_y = touchHandle.resolutionX - tp[i].x; + break; + default: + break; + } + + found_track = true; + return; + } + } + + /* No track #0 found... */ + if (found_track) + { + *pressed = 1; + found_track = false; + } +#else + touch_event_t touch_event; + static int touch_x = 0; + static int touch_y = 0; + + data->state = LV_INDEV_STATE_REL; + + if (kStatus_Success == FT5406_RT_GetSingleTouch(&touchHandle, &touch_event, &touch_x, &touch_y)) + { + if ((touch_event == kTouch_Down) || (touch_event == kTouch_Contact)) + { + data->state = LV_INDEV_STATE_PR; + } + } + + /*Set the last pressed coordinates*/ + data->point.y = touch_y; + data->point.x = touch_x; +#endif +} diff --git a/bsp/projects/nxpvee-ui/bsp/display_support.h b/bsp/projects/nxpvee-ui/bsp/display_support.h new file mode 100644 index 0000000..a01173c --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/display_support.h @@ -0,0 +1,71 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef LVGL_SUPPORT_H +#define LVGL_SUPPORT_H + +#include + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef BOARD_USE_FLEXIO_SMARTDMA +#define BOARD_USE_FLEXIO_SMARTDMA 1 +#endif + +#ifndef BOARD_LCD_S035 +#define BOARD_LCD_S035 0 +#endif + +#if BOARD_LCD_S035 +#define LCD_WIDTH 480 +#define LCD_HEIGHT 320 +#else +#define LCD_WIDTH 800 +#define LCD_HEIGHT 480 +#endif + +#define LCD_FB_BYTE_PER_PIXEL 2 +/* The virtual buffer for DBI panel, it should be ~1/10 screen size. */ +#define LCD_VIRTUAL_BUF_HEIGHT LCD_HEIGHT/10 +// (LCD_HEIGHT / 10) +#define LCD_VIRTUAL_BUF_SIZE LCD_WIDTH * LCD_VIRTUAL_BUF_HEIGHT +// (LCD_WIDTH * LCD_VIRTUAL_BUF_HEIGHT) + +/* LCD panel. */ +#define BOARD_LCD_RST_GPIO GPIO4 +#define BOARD_LCD_RST_PIN 7 +#define BOARD_LCD_TE_GPIO GPIO0 +#define BOARD_LCD_TE_PIN 13 +#define BOARD_LCD_CS_GPIO GPIO0 +#define BOARD_LCD_CS_PIN 12 +#define BOARD_LCD_RS_GPIO GPIO0 +#define BOARD_LCD_RS_PIN 7 +#define BOARD_LCD_INT_PORT PORT4 +#define BOARD_LCD_INT_GPIO GPIO4 +#define BOARD_LCD_INT_PIN 6 + +/******************************************************************************* + * API + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +void disp_sup_pre_init(void); +void disp_sup_disp_init(void); +void disp_sup_indev_init(void); +void disp_sup_flush(uint8_t* srcAddr, uint32_t startX, uint32_t startY, uint32_t endX, uint32_t endY, uint32_t number_pixel); +uint8_t* disp_sup_get_fb_address(); +void DEMO_InitTouch(void); +void DEMO_ReadTouch(int *pressed, int *touch_x, int *touch_y); + +#if defined(__cplusplus) +} +#endif + +#endif /*LVGL_SUPPORT_H */ diff --git a/bsp/projects/nxpvee-ui/bsp/microej_mbedtls_config.h b/bsp/projects/nxpvee-ui/bsp/microej_mbedtls_config.h new file mode 100644 index 0000000..4cca714 --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/microej_mbedtls_config.h @@ -0,0 +1,4372 @@ +/** + * \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 The Mbed TLS Contributors + * 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. + */ + +#ifndef ELS_PKC_MBEDTLS_CONFIG_H +#define ELS_PKC_MBEDTLS_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/**************************** MCUX ELS_PKC ********************************************/ +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" + +/* Compatibility macros across different devices */ +#ifndef PKC +#define PKC PKC0 +#endif + +/* If those defines are not defined on command line, by default turn them on to use HW acceleration with this mbedtls_config file. Comment to turn off port layer */ +#ifndef MBEDTLS_MCUX_USE_ELS +#define MBEDTLS_MCUX_USE_ELS +#endif + +#ifndef MBEDTLS_MCUX_USE_PKC +#define MBEDTLS_MCUX_USE_PKC +#endif + +/* Eanble usage of TRNG as entropy seeding source based upon Platform TRNG support and configurability*/ +#if defined(MCUX_ENABLE_TRNG_AS_ENTROPY_SEED) && \ + (defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0)) +#define MBEDTLS_MCUX_USE_TRNG_AS_ENTROPY_SEED +#endif + +/* Uncomment to enable HW acceleration, Comment to disable HW acceleration, use SW only */ + +/* Enable ELS */ +#if defined(ELS) +#if defined(MBEDTLS_MCUX_USE_ELS) + +/** + * Uncomment a macro to enable alternate implementation of specific base + * platform function +*/ + + #define MBEDTLS_MCUX_ELS_AES /* Enable use of ELS AES. */ + #define MBEDTLS_MCUX_ELS_AES_GCM /* Enable use of ELS AES. */ + #define MBEDTLS_MCUX_ELS_SHA256 /* Enable use of ELS SHA256. */ + #define MBEDTLS_MCUX_ELS_SHA512 /* Enable use of ELS SHA512. */ + + #define MBEDTLS_CTR_DRBG_ALT /* Enable use of ELS CTR DRBG. */ + +#endif /* MBEDTLS_MCUX_USE_ELS */ +#endif /* ELS */ + +/* Enable PKC */ +#if defined(PKC) +#if defined(MBEDTLS_MCUX_USE_PKC) + +/** + * Uncomment a macro to enable alternate implementation of specific base + * platform function +*/ + + #define MBEDTLS_MCUX_PKC_ECDH /* Enable use of PKC ECDH. */ +// #define MBEDTLS_MCUX_PKC_ECDSA /* Enable use of PKC ECDSA. */ + #define MBEDTLS_MCUX_PKC_RSA /* Enable use of PKC RSA. */ + +#endif /* MBEDTLS_MCUX_USE_PKC */ +#endif /* PKC */ + + +/* ======== Define ALT functions ====================================== */ +#if defined(MBEDTLS_MCUX_ELS_AES) + + #define MBEDTLS_AES_SETKEY_ENC_ALT + #define MBEDTLS_AES_SETKEY_DEC_ALT + #define MBEDTLS_AES_ENCRYPT_ALT + #define MBEDTLS_AES_DECRYPT_ALT + #define MBEDTLS_AES_CTX_ALT + + #define MBEDTLS_AES_CBC_ALT + #define MBEDTLS_AES_CTR_ALT + #define MBEDTLS_AES_CMAC_ALT + +/** + * \def MBEDTLS_CCM_USE_AES_CBC_MAC + * + * Uncomment this macro in case CCM should be used with AES CBC-MAC calling ELS IP. + * + */ +#define MBEDTLS_CCM_USE_AES_CBC_MAC + +#endif + +#if defined(MBEDTLS_MCUX_ELS_AES_GCM) + + #define MBEDTLS_AES_GCM_SETKEY_ALT + #define MBEDTLS_AES_GCM_STARTS_ALT + #define MBEDTLS_AES_GCM_UPDATE_ALT + #define MBEDTLS_AES_GCM_FINISH_ALT + +#endif + +#if defined(MBEDTLS_MCUX_ELS_SHA256) + + #define MBEDTLS_SHA256_CTX_ALT + #define MBEDTLS_SHA256_STARTS_ALT + #define MBEDTLS_SHA256_UPDATE_ALT + #define MBEDTLS_SHA256_FINISH_ALT + #define MBEDTLS_SHA256_FULL_ALT + #define MBEDTLS_SHA256_PROCESS_ALT + +#endif + +#if defined(MBEDTLS_MCUX_ELS_SHA512) + + #define MBEDTLS_SHA512_CTX_ALT + #define MBEDTLS_SHA512_STARTS_ALT + #define MBEDTLS_SHA512_UPDATE_ALT + #define MBEDTLS_SHA512_FINISH_ALT + #define MBEDTLS_SHA512_FULL_ALT + #define MBEDTLS_SHA512_PROCESS_ALT + +#endif + +#if defined(MBEDTLS_MCUX_PKC_ECDH) + + #define MBEDTLS_ECDH_GEN_PUBLIC_ALT + #define MBEDTLS_ECDH_COMPUTE_SHARED_ALT + #define MBEDTLS_ECDH_CANDO_ALT + +#endif + +#if defined(MBEDTLS_MCUX_PKC_ECDSA) + + #define MBEDTLS_ECDSA_SIGN_ALT + #define MBEDTLS_ECDSA_VERIFY_ALT + #define MBEDTLS_ECDSA_GENKEY_ALT + +#endif + +#if defined(MBEDTLS_MCUX_PKC_RSA) + + #define MBEDTLS_RSA_PUBLIC_ALT + #define MBEDTLS_RSA_PRIVATE_ALT + #define MBEDTLS_RSA_CTX_ALT + +#endif +/**************************** MCUX ELS_PKC end ****************************************/ +/** + * \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 (on some platforms) + * 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. + * + * \note If MBEDTLS_TIMING_C is set - to enable the semi-portable timing + * interface - timing.c will include time.h on suitable platforms + * regardless of the setting of MBEDTLS_HAVE_TIME, unless + * MBEDTLS_TIMING_ALT is used. See timing.c for more information. + */ +//#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 necessarily 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. + * + * An overview of how the value of mbedtls_calloc is determined: + * + * - if !MBEDTLS_PLATFORM_MEMORY + * - mbedtls_calloc = calloc + * - if MBEDTLS_PLATFORM_MEMORY + * - if (MBEDTLS_PLATFORM_CALLOC_MACRO && MBEDTLS_PLATFORM_FREE_MACRO): + * - mbedtls_calloc = MBEDTLS_PLATFORM_CALLOC_MACRO + * - if !(MBEDTLS_PLATFORM_CALLOC_MACRO && MBEDTLS_PLATFORM_FREE_MACRO): + * - Dynamic setup via mbedtls_platform_set_calloc_free is now possible with a default value MBEDTLS_PLATFORM_STD_CALLOC. + * - How is MBEDTLS_PLATFORM_STD_CALLOC handled? + * - if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS: + * - MBEDTLS_PLATFORM_STD_CALLOC is not set to anything; + * - MBEDTLS_PLATFORM_STD_MEM_HDR can be included if present; + * - if !MBEDTLS_PLATFORM_NO_STD_FUNCTIONS: + * - if MBEDTLS_PLATFORM_STD_CALLOC is present: + * - User-defined MBEDTLS_PLATFORM_STD_CALLOC is respected; + * - if !MBEDTLS_PLATFORM_STD_CALLOC: + * - MBEDTLS_PLATFORM_STD_CALLOC = calloc + * + * - At this point the presence of MBEDTLS_PLATFORM_STD_CALLOC is checked. + * - if !MBEDTLS_PLATFORM_STD_CALLOC + * - MBEDTLS_PLATFORM_STD_CALLOC = uninitialized_calloc + * + * - mbedtls_calloc = MBEDTLS_PLATFORM_STD_CALLOC. + * + * Defining MBEDTLS_PLATFORM_CALLOC_MACRO and #MBEDTLS_PLATFORM_STD_CALLOC at the same time is not possible. + * MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_FREE_MACRO must both be defined or undefined at the same time. + * #MBEDTLS_PLATFORM_STD_CALLOC and #MBEDTLS_PLATFORM_STD_FREE do not have to be defined at the same time, as, if they are used, + * dynamic setup of these functions is possible. See the tree above to see how are they handled in all cases. + * An uninitialized #MBEDTLS_PLATFORM_STD_CALLOC always fails, returning a null pointer. + * An uninitialized #MBEDTLS_PLATFORM_STD_FREE does not do anything. + * + * 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_VSNPRINTF_ALT +//#define MBEDTLS_PLATFORM_NV_SEED_ALT +//#define MBEDTLS_PLATFORM_SETUP_TEARDOWN_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 + +/** + * 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 + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions and features so that they generate a warning if + * used. Functionality 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 this functionality. + * + * 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 and features. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions and features so that they generate an error if + * used. Functionality 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 this functionality. + * + * Uncomment to get errors on using deprecated functions and features. + */ +//#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: + * 1. The function will invoke the macro MBEDTLS_PARAM_FAILED(). + * 2. If MBEDTLS_PARAM_FAILED() did not terminate the program, the function + * will immediately return. If the function returns an Mbed TLS error code, + * the error code in this case is MBEDTLS_ERR_xxx_BAD_INPUT_DATA. + * + * When defining this flag, you also need to arrange a definition for + * MBEDTLS_PARAM_FAILED(). You can do this by any of the following methods: + * - By default, the library defines MBEDTLS_PARAM_FAILED() to call a + * function mbedtls_param_failed(), but the library does not define this + * function. If you do not make any other arrangements, you must provide + * the function mbedtls_param_failed() in your application. + * See `platform_util.h` for its prototype. + * - If you enable the macro #MBEDTLS_CHECK_PARAMS_ASSERT, then the + * library defines MBEDTLS_PARAM_FAILED(\c cond) to be `assert(cond)`. + * You can still supply an alternative definition of + * MBEDTLS_PARAM_FAILED(), which may call `assert`. + * - If you define a macro MBEDTLS_PARAM_FAILED() before including `config.h` + * or you uncomment the definition of MBEDTLS_PARAM_FAILED() in `config.h`, + * the library will call the macro that you defined and will not supply + * its own version. Note that if MBEDTLS_PARAM_FAILED() calls `assert`, + * you need to enable #MBEDTLS_CHECK_PARAMS_ASSERT so that library source + * files include ``. + * + * Uncomment to enable validation of application-controlled parameters. + */ +//#define MBEDTLS_CHECK_PARAMS + +/** + * \def MBEDTLS_CHECK_PARAMS_ASSERT + * + * Allow MBEDTLS_PARAM_FAILED() to call `assert`, and make it default to + * `assert`. This macro is only used if #MBEDTLS_CHECK_PARAMS is defined. + * + * If this macro is not defined, then MBEDTLS_PARAM_FAILED() defaults to + * calling a function mbedtls_param_failed(). See the documentation of + * #MBEDTLS_CHECK_PARAMS for details. + * + * Uncomment to allow MBEDTLS_PARAM_FAILED() to call `assert`. + */ +//#define MBEDTLS_CHECK_PARAMS_ASSERT + +/** \} 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, please 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 overridden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt + * must stay untouched. + * + * \note If you use the AES_xxx_ALT macros, then it 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. + * + * \warning If both MBEDTLS_ECDSA_SIGN_ALT and MBEDTLS_ECDSA_DETERMINISTIC are + * enabled, then the deterministic ECDH signature functions pass the + * the static HMAC-DRBG as RNG to mbedtls_ecdsa_sign(). Therefore + * alternative implementations should use the RNG only for generating + * the ephemeral key and nothing else. If this is not possible, then + * MBEDTLS_ECDSA_DETERMINISTIC should be disabled and an alternative + * implementation should be provided for mbedtls_ecdsa_sign_det_ext() + * (and for mbedtls_ecdsa_sign_det() too if backward compatibility is + * desirable). + * + */ +//#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. + * + * The original implementation can in addition be removed by setting the + * MBEDTLS_ECP_NO_FALLBACK option, in which case any function for which the + * corresponding MBEDTLS_ECP__FUNCTION_NAME__ALT macro is defined will not be + * able to fallback to curves not supported by the alternative implementation. + * + * 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 set 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 + * for the operation is supported by your implementation (i.e. your + * mbedtls_internal_ecp_grp_capable() function returns 1 for this group). If the + * group is not supported by your implementation, then the original Mbed TLS + * implementation of ecp_double_jac() is used instead, unless this fallback + * behaviour is disabled by setting MBEDTLS_ECP_NO_FALLBACK (in which case + * ecp_double_jac() will return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE). + * + * The function prototypes and the definition of mbedtls_ecp_group and + * mbedtls_ecp_point will not change based on MBEDTLS_ECP_INTERNAL_ALT, so your + * implementation of mbedtls_internal_ecp__function_name__ must be compatible + * with their definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +/* Required for all the functions in this section */ +//#define MBEDTLS_ECP_INTERNAL_ALT +/* Turn off software fallback for curves not supported in hardware */ +//#define MBEDTLS_ECP_NO_FALLBACK +/* 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_CHECK_RETURN_WARNING + * + * If this macro is defined, emit a compile-time warning if application code + * calls a function without checking its return value, but the return value + * should generally be checked in portable applications. + * + * This is only supported on platforms where #MBEDTLS_CHECK_RETURN is + * implemented. Otherwise this option has no effect. + * + * Uncomment to get warnings on using fallible functions without checking + * their return value. + * + * \note This feature is a work in progress. + * Warnings will be added to more functions in the future. + * + * \note A few functions are considered critical, and ignoring the return + * value of these functions will trigger a warning even if this + * macro is not defined. To completely disable return value check + * warnings, define #MBEDTLS_CHECK_RETURN with an empty expansion. + */ +//#define MBEDTLS_CHECK_RETURN_WARNING + +/** + * \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_CTR_DRBG_USE_128_BIT_KEY + * + * Uncomment this macro to use a 128-bit key in the CTR_DRBG module. + * By default, CTR_DRBG uses a 256-bit key. + */ +//#define MBEDTLS_CTR_DRBG_USE_128_BIT_KEY + +/** + * \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_REMOVE_3DES_CIPHERSUITES + * + * Remove 3DES ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on 3DES 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. + * + * A man-in-the-browser attacker can recover authentication tokens sent through + * a TLS connection using a 3DES based cipher suite (see "On the Practical + * (In-)Security of 64-bit Block Ciphers" by Karthikeyan Bhargavan and Gaëtan + * Leurent, see https://sweet32.info/SWEET32_CCS16.pdf). If this attack falls + * in your threat model or you are unsure, then you should keep this option + * enabled to remove 3DES based cipher suites. + * + * Comment this macro to keep 3DES in the default ciphersuite list. + */ +#define MBEDTLS_REMOVE_3DES_CIPHERSUITES + +/** + * Enable the verified implementations of ECDH primitives from Project Everest + * (currently only Curve25519). This feature changes the layout of ECDH + * contexts and therefore is a compatibility break for applications that access + * fields of a mbedtls_ecdh_context structure directly. See also + * MBEDTLS_ECDH_LEGACY_CONTEXT in include/mbedtls/ecdh.h. + */ +//#define MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED + +/** + * \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 + */ +/* Short Weierstrass curves (supporting ECP, ECDH, ECDSA) */ +#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 +/* Montgomery curves (supporting ECP), NOT supported by ELS PKC*/ +//#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_NO_INTERNAL_RNG + * + * When this option is disabled, mbedtls_ecp_mul() will make use of an + * internal RNG when called with a NULL \c f_rng argument, in order to protect + * against some side-channel attacks. + * + * This protection introduces a dependency of the ECP module on one of the + * DRBG modules. For very constrained implementations that don't require this + * protection (for example, because you're only doing signature verification, + * so not manipulating any secret, or because local/physical side-channel + * attacks are outside your threat model), it might be desirable to get rid of + * that dependency. + * + * \warning Enabling this option makes some uses of ECP vulnerable to some + * side-channel attacks. Only enable it if you know that's not a problem for + * your use case. + * + * Uncomment this macro to disable some counter-measures in ECP. + */ +//#define MBEDTLS_ECP_NO_INTERNAL_RNG + +/** + * \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. + * + * This option: + * - Adds xxx_restartable() variants of existing operations in the + * following modules, with corresponding restart context types: + * - ECP (for Short Weierstrass curves only): scalar multiplication (mul), + * linear combination (muladd); + * - ECDSA: signature generation & verification; + * - PK: signature generation & verification; + * - X509: certificate chain verification. + * - Adds mbedtls_ecdh_enable_restart() in the ECDH module. + * - Changes the behaviour of TLS 1.2 clients (not servers) when using the + * ECDHE-ECDSA key exchange (not other key exchanges) to make all ECC + * computations restartable: + * - ECDH operations from the key exchange, only for Short Weierstrass + * curves; + * - verification of the server's key exchange signature; + * - verification of the server's certificate chain; + * - generation of the client's signature if client authentication is used, + * with an ECC key/certificate. + * + * \note In the cases above, the usual SSL/TLS functions, such as + * mbedtls_ssl_handshake(), can now return + * MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS. + * + * \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, MBEDTLS_ECDSA_XXX_ALT, + * MBEDTLS_ECDH_LEGACY_CONTEXT, and MBEDTLS_USE_PSA_CRYPTO. + * + * Requires: MBEDTLS_ECP_C + * + * Uncomment this macro to enable restartable ECC computations. + */ +//#define MBEDTLS_ECP_RESTARTABLE + +/** + * \def MBEDTLS_ECDH_LEGACY_CONTEXT + * + * Use a backward compatible ECDH context. + * + * Mbed TLS supports two formats for ECDH contexts (#mbedtls_ecdh_context + * defined in `ecdh.h`). For most applications, the choice of format makes + * no difference, since all library functions can work with either format, + * except that the new format is incompatible with MBEDTLS_ECP_RESTARTABLE. + + * The new format used when this option is disabled is smaller + * (56 bytes on a 32-bit platform). In future versions of the library, it + * will support alternative implementations of ECDH operations. + * The new format is incompatible with applications that access + * context fields directly and with restartable ECP operations. + * + * Define this macro if you enable MBEDTLS_ECP_RESTARTABLE or if you + * want to access ECDH context fields directly. Otherwise you should + * comment out this macro definition. + * + * This option has no effect if #MBEDTLS_ECDH_C is not enabled. + * + * \note This configuration option is experimental. Future versions of the + * library may modify the way the ECDH context layout is configured + * and may modify the layout of the new context type. + */ +#define MBEDTLS_ECDH_LEGACY_CONTEXT + +/** + * \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, MBEDTLS_ECDSA_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_ECDSA_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_RSA_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 + +/* MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER + * + * Enable key identifiers that encode a key owner identifier. + * + * The owner of a key is identified by a value of type ::mbedtls_key_owner_id_t + * which is currently hard-coded to be int32_t. + * + * Note that this option is meant for internal use only and may be removed + * without notice. It is incompatible with MBEDTLS_USE_PSA_CRYPTO. + */ +//#define MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER + +/** + * \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() and 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_PSA_CRYPTO_BUILTIN_KEYS + * + * Enable support for platform built-in keys. If you enable this feature, + * you must implement the function mbedtls_psa_platform_get_builtin_key(). + * See the documentation of that function for more information. + * + * Built-in keys are typically derived from a hardware unique key or + * stored in a secure element. + * + * Requires: MBEDTLS_PSA_CRYPTO_C. + * + * \warning This interface is experimental and may change or be removed + * without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS + +/** \def MBEDTLS_PSA_CRYPTO_CLIENT + * + * Enable support for PSA crypto client. + * + * \note This option allows to include the code necessary for a PSA + * crypto client when the PSA crypto implementation is not included in + * the library (MBEDTLS_PSA_CRYPTO_C disabled). The code included is the + * code to set and get PSA key attributes. + * The development of PSA drivers partially relying on the library to + * fulfill the hardware gaps is another possible usage of this option. + * + * \warning This interface is experimental and may change or be removed + * without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_CLIENT + +/** \def MBEDTLS_PSA_CRYPTO_DRIVERS + * + * Enable support for the experimental PSA crypto driver interface. + * + * Requires: MBEDTLS_PSA_CRYPTO_C + * + * \warning This interface is experimental and may change or be removed + * without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_DRIVERS + +/** \def MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + * + * Make the PSA Crypto module use an external random generator provided + * by a driver, instead of Mbed TLS's entropy and DRBG modules. + * + * \note This random generator must deliver random numbers with cryptographic + * quality and high performance. It must supply unpredictable numbers + * with a uniform distribution. The implementation of this function + * is responsible for ensuring that the random generator is seeded + * with sufficient entropy. If you have a hardware TRNG which is slow + * or delivers non-uniform output, declare it as an entropy source + * with mbedtls_entropy_add_source() instead of enabling this option. + * + * If you enable this option, you must configure the type + * ::mbedtls_psa_external_random_context_t in psa/crypto_platform.h + * and define a function called mbedtls_psa_external_get_random() + * with the following prototype: + * ``` + * psa_status_t mbedtls_psa_external_get_random( + * mbedtls_psa_external_random_context_t *context, + * uint8_t *output, size_t output_size, size_t *output_length); + * ); + * ``` + * The \c context value is initialized to 0 before the first call. + * The function must fill the \c output buffer with \c output_size bytes + * of random data and set \c *output_length to \c output_size. + * + * Requires: MBEDTLS_PSA_CRYPTO_C + * + * \warning If you enable this option, code that uses the PSA cryptography + * interface will not use any of the entropy sources set up for + * the entropy module, nor the NV seed that MBEDTLS_ENTROPY_NV_SEED + * enables. + * + * \note This option is experimental and may be removed without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + +/** + * \def MBEDTLS_PSA_CRYPTO_SPM + * + * When MBEDTLS_PSA_CRYPTO_SPM is defined, the code is built for SPM (Secure + * Partition Manager) integration which separates the code into two parts: a + * NSPE (Non-Secure Process Environment) and an SPE (Secure Process + * Environment). + * + * Module: library/psa_crypto.c + * Requires: MBEDTLS_PSA_CRYPTO_C + * + */ +//#define MBEDTLS_PSA_CRYPTO_SPM + +/** + * \def MBEDTLS_PSA_INJECT_ENTROPY + * + * Enable support for entropy injection at first boot. This feature is + * required on systems that do not have a built-in entropy source (TRNG). + * This feature is currently not supported on systems that have a built-in + * entropy source. + * + * Requires: MBEDTLS_PSA_CRYPTO_STORAGE_C, MBEDTLS_ENTROPY_NV_SEED + * + */ +//#define MBEDTLS_PSA_INJECT_ENTROPY + +/** + * \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 reasonable 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_SHA512_SMALLER + * + * Enable an implementation of SHA-512 that has lower ROM footprint but also + * lower performance. + * + * Uncomment to enable the smaller implementation of SHA512. + */ +//#define MBEDTLS_SHA512_SMALLER + +/** + * \def MBEDTLS_SHA512_NO_SHA384 + * + * Disable the SHA-384 option of the SHA-512 module. Use this to save some + * code size on devices that don't use SHA-384. + * + * Requires: MBEDTLS_SHA512_C + * + * Uncomment to disable SHA-384 + */ +//#define MBEDTLS_SHA512_NO_SHA384 + +/** + * \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_RECORD_CHECKING + * + * Enable the function mbedtls_ssl_check_record() which can be used to check + * the validity and authenticity of an incoming record, to verify that it has + * not been seen before. These checks are performed without modifying the + * externally visible state of the SSL context. + * + * See mbedtls_ssl_check_record() for more information. + * + * Uncomment to enable support for record checking. + */ +#define MBEDTLS_SSL_RECORD_CHECKING + +/** + * \def MBEDTLS_SSL_DTLS_CONNECTION_ID + * + * Enable support for the DTLS Connection ID extension + * (version draft-ietf-tls-dtls-connection-id-05, + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05) + * which allows to identify DTLS connections across changes + * in the underlying transport. + * + * Setting this option enables the SSL APIs `mbedtls_ssl_set_cid()`, + * `mbedtls_ssl_get_peer_cid()` and `mbedtls_ssl_conf_cid()`. + * See the corresponding documentation for more information. + * + * \warning The Connection ID extension is still in draft state. + * We make no stability promises for the availability + * or the shape of the API controlled by this option. + * + * The maximum lengths of outgoing and incoming CIDs can be configured + * through the options + * - MBEDTLS_SSL_CID_OUT_LEN_MAX + * - MBEDTLS_SSL_CID_IN_LEN_MAX. + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Uncomment to enable the Connection ID extension. + */ +//#define MBEDTLS_SSL_DTLS_CONNECTION_ID + +/** + * \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_CONTEXT_SERIALIZATION + * + * Enable serialization of the TLS context structures, through use of the + * functions mbedtls_ssl_context_save() and mbedtls_ssl_context_load(). + * + * This pair of functions allows one side of a connection to serialize the + * context associated with the connection, then free or re-use that context + * while the serialized state is persisted elsewhere, and finally deserialize + * that state to a live context for resuming read/write operations on the + * connection. From a protocol perspective, the state of the connection is + * unaffected, in particular this is entirely transparent to the peer. + * + * Note: this is distinct from TLS session resumption, which is part of the + * protocol and fully visible by the peer. TLS session resumption enables + * establishing new connections associated to a saved session with shorter, + * lighter handshakes, while context serialization is a local optimization in + * handling a single, potentially long-lived connection. + * + * Enabling these APIs makes some SSL structures larger, as 64 extra bytes are + * saved after the handshake to allow for more efficient serialization, so if + * you don't need this feature you'll save RAM by disabling it. + * + * Requires: MBEDTLS_GCM_C or MBEDTLS_CCM_C or MBEDTLS_CHACHAPOLY_C + * + * Comment to disable the context serialization APIs. + */ +#define MBEDTLS_SSL_CONTEXT_SERIALIZATION + +/** + * \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 RFC 7627: Session Hash and Extended Master Secret + * Extension. + * + * This was introduced as "the proper fix" to the Triple Handshake family 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 RFC 7507: Fallback Signaling Cipher Suite Value (SCSV) + * for Preventing Protocol Downgrade Attacks. + * + * 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_KEEP_PEER_CERTIFICATE + * + * This option controls the availability of the API mbedtls_ssl_get_peer_cert() + * giving access to the peer's certificate after completion of the handshake. + * + * Unless you need mbedtls_ssl_peer_cert() in your application, it is + * recommended to disable this option for reduced RAM usage. + * + * \note If this option is disabled, mbedtls_ssl_get_peer_cert() is still + * defined, but always returns \c NULL. + * + * \note This option has no influence on the protection against the + * triple handshake attack. Even if it is disabled, Mbed TLS will + * still ensure that certificates do not change during renegotiation, + * for example by keeping a hash of the peer's certificate. + * + * Comment this macro to disable storing the peer's certificate + * after the handshake. + */ +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * \deprecated This option is deprecated and will be removed in a future + * version of Mbed TLS. + * + * 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). + * + * \deprecated This option is deprecated and will be removed in a future + * version of Mbed TLS. + * + * 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 + * + * \deprecated This option is deprecated and will be removed in a future + * version of Mbed TLS. + * + * 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_TLS1_3_EXPERIMENTAL + * + * This macro is used to selectively enable experimental parts + * of the code that contribute to the ongoing development of + * the prototype TLS 1.3 and DTLS 1.3 implementation, and provide + * no other purpose. + * + * \warning TLS 1.3 and DTLS 1.3 aren't yet supported in Mbed TLS, + * and no feature exposed through this macro is part of the + * public API. In particular, features under the control + * of this macro are experimental and don't come with any + * stability guarantees. + * + * Uncomment this macro to enable experimental and partial + * functionality specific to TLS 1.3. + */ +//#define MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + +/** + * \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 be 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_SRTP + * + * Enable support for negotiation of DTLS-SRTP (RFC 5764) + * through the use_srtp extension. + * + * \note This feature provides the minimum functionality required + * to negotiate the use of DTLS-SRTP and to allow the derivation of + * the associated SRTP packet protection key material. + * In particular, the SRTP packet protection itself, as well as the + * demultiplexing of RTP and DTLS packets at the datagram layer + * (see Section 5 of RFC 5764), are not handled by this feature. + * Instead, after successful completion of a handshake negotiating + * the use of DTLS-SRTP, the extended key exporter API + * mbedtls_ssl_conf_export_keys_ext_cb() should be used to implement + * the key exporter described in Section 4.2 of RFC 5764 and RFC 5705 + * (this is implemented in the SSL example programs). + * The resulting key should then be passed to an SRTP stack. + * + * Setting this option enables the runtime API + * mbedtls_ssl_conf_dtls_srtp_protection_profiles() + * through which the supported DTLS-SRTP protection + * profiles can be configured. You must call this API at + * runtime if you wish to negotiate the use of DTLS-SRTP. + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Uncomment this to enable support for use_srtp extension. + */ +//#define MBEDTLS_SSL_DTLS_SRTP + +/** + * \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 (maintenance 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 will 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 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_SSL_VARIABLE_BUFFER_LENGTH + * + * When this option is enabled, the SSL buffer will be resized automatically + * based on the negotiated maximum fragment length in each direction. + * + * Requires: MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + */ +//#define MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + +/** + * 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 + +/** + * \def MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN + * + * Enable testing of the constant-flow nature of some sensitive functions with + * clang's MemorySanitizer. This causes some existing tests to also test + * this non-functional property of the code under test. + * + * This setting requires compiling with clang -fsanitize=memory. The test + * suites can then be run normally. + * + * \warning This macro is only used for extended testing; it is not considered + * part of the library's API, so it may change or disappear at any time. + * + * Uncomment to enable testing of the constant-flow nature of selected code. + */ +//#define MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN + +/** + * \def MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND + * + * Enable testing of the constant-flow nature of some sensitive functions with + * valgrind's memcheck tool. This causes some existing tests to also test + * this non-functional property of the code under test. + * + * This setting requires valgrind headers for building, and is only useful for + * testing if the tests suites are run with valgrind's memcheck. This can be + * done for an individual test suite with 'valgrind ./test_suite_xxx', or when + * using CMake, this can be done for all test suites with 'make memcheck'. + * + * \warning This macro is only used for extended testing; it is not considered + * part of the library's API, so it may change or disappear at any time. + * + * Uncomment to enable testing of the constant-flow nature of selected code. + */ +//#define MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND + +/** + * \def MBEDTLS_TEST_HOOKS + * + * Enable features for invasive testing such as introspection functions and + * hooks for fault injection. This enables additional unit tests. + * + * Merely enabling this feature should not change the behavior of the product. + * It only adds new code, and new branching points where the default behavior + * is the same as when this feature is disabled. + * However, this feature increases the attack surface: there is an added + * risk of vulnerabilities, and more gadgets that can make exploits easier. + * Therefore this feature must never be enabled in production. + * + * See `docs/architecture/testing/mbed-crypto-invasive-testing.md` for more + * information. + * + * Uncomment to enable invasive tests. + */ +//#define MBEDTLS_TEST_HOOKS + +/** + * \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_USE_PSA_CRYPTO + * + * Make the X.509 and TLS library use PSA for cryptographic operations, and + * enable new APIs for using keys handled by PSA Crypto. + * + * \note Development of this option is currently in progress, and parts of Mbed + * TLS's X.509 and TLS modules are not ported to PSA yet. However, these parts + * will still continue to work as usual, so enabling this option should not + * break backwards compatibility. + * + * \note See docs/use-psa-crypto.md for a complete description of what this + * option currently does, and of parts that are not affected by it so far. + * + * \warning This option enables new Mbed TLS APIs which are currently + * considered experimental and may change in incompatible ways at any time. + * That is, the APIs enabled by this option are not covered by the usual + * promises of API stability. + * + * Requires: MBEDTLS_PSA_CRYPTO_C. + * + * Uncomment this to enable internal use of PSA Crypto and new associated APIs. + */ +//#define MBEDTLS_USE_PSA_CRYPTO + +/** + * \def MBEDTLS_PSA_CRYPTO_CONFIG + * + * This setting allows support for cryptographic mechanisms through the PSA + * API to be configured separately from support through the mbedtls API. + * + * When this option is disabled, the PSA API exposes the cryptographic + * mechanisms that can be implemented on top of the `mbedtls_xxx` API + * configured with `MBEDTLS_XXX` symbols. + * + * When this option is enabled, the PSA API exposes the cryptographic + * mechanisms requested by the `PSA_WANT_XXX` symbols defined in + * include/psa/crypto_config.h. The corresponding `MBEDTLS_XXX` settings are + * automatically enabled if required (i.e. if no PSA driver provides the + * mechanism). You may still freely enable additional `MBEDTLS_XXX` symbols + * in config.h. + * + * If the symbol #MBEDTLS_PSA_CRYPTO_CONFIG_FILE is defined, it specifies + * an alternative header to include instead of include/psa/crypto_config.h. + * + * If you enable this option and write your own configuration file, you must + * include mbedtls/config_psa.h in your configuration file. The default + * provided mbedtls/config.h contains the necessary inclusion. + * + * This feature is still experimental and is not ready for production since + * it is not completed. + */ +//#define MBEDTLS_PSA_CRYPTO_CONFIG + +/** + * \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_TRUSTED_CERTIFICATE_CALLBACK + * + * If set, this enables the X.509 API `mbedtls_x509_crt_verify_with_ca_cb()` + * and the SSL API `mbedtls_ssl_conf_ca_cb()` which allow users to configure + * the set of trusted certificates through a callback instead of a linked + * list. + * + * This is useful for example in environments where a large number of trusted + * certificates is present and storing them in a linked list isn't efficient + * enough, or when the set of trusted certificates changes frequently. + * + * See the documentation of `mbedtls_x509_crt_verify_with_ca_cb()` and + * `mbedtls_ssl_conf_ca_cb()` for more information. + * + * Uncomment to enable trusted certificate callbacks. + */ +//#define MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK + +/** + * \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 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 or x86-32. + * + * \note AESNI is only supported with certain compilers and target options: + * - Visual Studio 2013: supported. + * - GCC, x86-64, target not explicitly supporting AESNI: + * requires MBEDTLS_HAVE_ASM. + * - GCC, x86-32, target not explicitly supporting AESNI: + * not supported. + * - GCC, x86-64 or x86-32, target supporting AESNI: supported. + * For this assembly-less implementation, you must currently compile + * `library/aesni.c` and `library/aes.c` with machine options to enable + * SSE2 and AESNI instructions: `gcc -msse2 -maes -mpclmul` or + * `clang -maes -mpclmul`. + * - Non-x86 targets: this option is silently ignored. + * - Other compilers: this option is silently ignored. + * + * \note + * Above, "GCC" includes compatible compilers such as Clang. + * The limitations on target support are likely to be relaxed in the future. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM (on some platforms, see note) + * + * This modules adds support for the AES-NI instructions on x86. + */ +#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 avoiding 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. + * + * \note When #MBEDTLS_CMAC_ALT is active, meaning that the underlying + * implementation of the CMAC algorithm is provided by an alternate + * implementation, that alternate implementation may opt to not support + * AES-192 or 3DES as underlying block ciphers for the CMAC operation. + * + * 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 \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY above. + * + * \note To achieve a 256-bit security strength with CTR_DRBG, + * you must use AES-256 *and* use sufficient entropy. + * See ctr_drbg.h for more details. + * + * 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/3DES are considered weak ciphers and their 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, + * and at least one MBEDTLS_ECP_DP_XXX_ENABLED for a + * short Weierstrass curve. + */ +#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). + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C or MBEDTLS_ARIA_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 generator. + */ +#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://mbed-tls.readthedocs.io/en/latest/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 (asymmetric) 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 (asymmetric) 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 (asymmetric) 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 via the pkcs11-helper library. + * + * \deprecated This option is deprecated and will be removed in a future + * version of Mbed TLS. + * + * 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_PSA_CRYPTO_C + * + * Enable the Platform Security Architecture cryptography API. + * + * Module: library/psa_crypto.c + * + * Requires: either MBEDTLS_CTR_DRBG_C and MBEDTLS_ENTROPY_C, + * or MBEDTLS_HMAC_DRBG_C and MBEDTLS_ENTROPY_C, + * or MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. + * + */ +//#define MBEDTLS_PSA_CRYPTO_C + +/** + * \def MBEDTLS_PSA_CRYPTO_SE_C + * + * Enable secure element support in the Platform Security Architecture + * cryptography API. + * + * \warning This feature is not yet suitable for production. It is provided + * for API evaluation and testing purposes only. + * + * Module: library/psa_crypto_se.c + * + * Requires: MBEDTLS_PSA_CRYPTO_C, MBEDTLS_PSA_CRYPTO_STORAGE_C + * + */ +//#define MBEDTLS_PSA_CRYPTO_SE_C + +/** + * \def MBEDTLS_PSA_CRYPTO_STORAGE_C + * + * Enable the Platform Security Architecture persistent key storage. + * + * Module: library/psa_crypto_storage.c + * + * Requires: MBEDTLS_PSA_CRYPTO_C, + * either MBEDTLS_PSA_ITS_FILE_C or a native implementation of + * the PSA ITS interface + */ +//#define MBEDTLS_PSA_CRYPTO_STORAGE_C + +/** + * \def MBEDTLS_PSA_ITS_FILE_C + * + * Enable the emulation of the Platform Security Architecture + * Internal Trusted Storage (PSA ITS) over files. + * + * Module: library/psa_its_file.c + * + * Requires: MBEDTLS_FS_IO + */ +//#define MBEDTLS_PSA_ITS_FILE_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 && + * ( MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_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://mbed-tls.readthedocs.io/en/latest/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 The timing module will include time.h on suitable platforms + * regardless of the setting of MBEDTLS_HAVE_TIME, unless + * MBEDTLS_TIMING_ALT is used. See timing.c for more information. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://mbed-tls.readthedocs.io/en/latest/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: General configuration options + * + * This section contains Mbed TLS build settings that are not associated + * with a particular module. + * + * \{ + */ + +/** + * \def MBEDTLS_CONFIG_FILE + * + * If defined, this is a header which will be included instead of + * `"mbedtls/config.h"`. + * This header file specifies the compile-time configuration of Mbed TLS. + * Unlike other configuration options, this one must be defined on the + * compiler command line: a definition in `config.h` would have no effect. + * + * This macro is expanded after an \#include directive. This is a popular but + * non-standard feature of the C language, so this feature is only available + * with compilers that perform macro expansion on an \#include line. + * + * The value of this symbol is typically a path in double quotes, either + * absolute or relative to a directory on the include search path. + */ +//#define MBEDTLS_CONFIG_FILE "mbedtls/config.h" + +/** + * \def MBEDTLS_USER_CONFIG_FILE + * + * If defined, this is a header which will be included after + * `"mbedtls/config.h"` or #MBEDTLS_CONFIG_FILE. + * This allows you to modify the default configuration, including the ability + * to undefine options that are enabled by default. + * + * This macro is expanded after an \#include directive. This is a popular but + * non-standard feature of the C language, so this feature is only available + * with compilers that perform macro expansion on an \#include line. + * + * The value of this symbol is typically a path in double quotes, either + * absolute or relative to a directory on the include search path. + */ +//#define MBEDTLS_USER_CONFIG_FILE "/dev/null" + +/** + * \def MBEDTLS_PSA_CRYPTO_CONFIG_FILE + * + * If defined, this is a header which will be included instead of + * `"psa/crypto_config.h"`. + * This header file specifies which cryptographic mechanisms are available + * through the PSA API when #MBEDTLS_PSA_CRYPTO_CONFIG is enabled, and + * is not used when #MBEDTLS_PSA_CRYPTO_CONFIG is disabled. + * + * This macro is expanded after an \#include directive. This is a popular but + * non-standard feature of the C language, so this feature is only available + * with compilers that perform macro expansion on an \#include line. + * + * The value of this symbol is typically a path in double quotes, either + * absolute or relative to a directory on the include search path. + */ +//#define MBEDTLS_PSA_CRYPTO_CONFIG_FILE "psa/crypto_config.h" + +/** + * \def MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE + * + * If defined, this is a header which will be included after + * `"psa/crypto_config.h"` or #MBEDTLS_PSA_CRYPTO_CONFIG_FILE. + * This allows you to modify the default configuration, including the ability + * to undefine options that are enabled by default. + * + * This macro is expanded after an \#include directive. This is a popular but + * non-standard feature of the C language, so this feature is only available + * with compilers that perform macro expansion on an \#include line. + * + * The value of this symbol is typically a path in double quotes, either + * absolute or relative to a directory on the include search path. + */ +//#define MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE "/dev/null" + +/** \} name SECTION: General configuration options */ + +/** + * \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. + * \{ + */ +/* The Doxygen documentation here is used when a user comments out a + * setting and runs doxygen themselves. On the other hand, when we typeset + * the full documentation including disabled settings, the documentation + * in specific modules' header files is used if present. When editing this + * file, make sure that each option is documented in exactly one place, + * plus optionally a same-line Doxygen comment here if there is a Doxygen + * comment in the specific module. */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum window 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 */ + +/* 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. Normally determined automatically from the configured curves. */ +//#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. */ + +/** \def MBEDTLS_PLATFORM_STD_CALLOC + * + * Default allocator to use, can be undefined. + * It must initialize the allocated buffer memory to zeroes. + * The size of the buffer is the product of the two parameters. + * The calloc function returns either a null pointer or a pointer to the allocated space. + * If the product is 0, the function may either return NULL or a valid pointer to an array of size 0 which is a valid input to the deallocation function. + * An uninitialized #MBEDTLS_PLATFORM_STD_CALLOC always fails, returning a null pointer. + * See the description of #MBEDTLS_PLATFORM_MEMORY for more details. + * The corresponding deallocation function is #MBEDTLS_PLATFORM_STD_FREE. + */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc + +/** \def MBEDTLS_PLATFORM_STD_FREE + * + * Default free to use, can be undefined. + * NULL is a valid parameter, and the function must do nothing. + * A non-null parameter will always be a pointer previously returned by #MBEDTLS_PLATFORM_STD_CALLOC and not yet freed. + * An uninitialized #MBEDTLS_PLATFORM_STD_FREE does not do anything. + * See the description of #MBEDTLS_PLATFORM_MEMORY for more details (same principles as for MBEDTLS_PLATFORM_STD_CALLOC apply). + */ +//#define MBEDTLS_PLATFORM_STD_FREE free +//#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 correctly 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 the following 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. See MBEDTLS_PLATFORM_STD_CALLOC for requirements. */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined. See MBEDTLS_PLATFORM_STD_FREE for requirements. */ +//#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 correctly zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_VSNPRINTF_MACRO vsnprintf /**< Default vsnprintf 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, the library provides + * a default definition. If the macro #MBEDTLS_CHECK_PARAMS_ASSERT + * is defined, the default definition is `assert(cond)`, + * otherwise the default definition calls a function + * mbedtls_param_failed(). This function is declared in + * `platform_util.h` for the benefit of the library, but + * 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). + * If you define this macro to call `assert`, also define + * #MBEDTLS_CHECK_PARAMS_ASSERT so that library source files + * include ``. + * + * 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 ) + +/** \def MBEDTLS_CHECK_RETURN + * + * This macro is used at the beginning of the declaration of a function + * to indicate that its return value should be checked. It should + * instruct the compiler to emit a warning or an error if the function + * is called without checking its return value. + * + * There is a default implementation for popular compilers in platform_util.h. + * You can override the default implementation by defining your own here. + * + * If the implementation here is empty, this will effectively disable the + * checking of functions' return values. + */ +//#define MBEDTLS_CHECK_RETURN __attribute__((__warn_unused_result__)) + +/** \def MBEDTLS_IGNORE_RETURN + * + * This macro requires one argument, which should be a C function call. + * If that function call would cause a #MBEDTLS_CHECK_RETURN warning, this + * warning is suppressed. + */ +//#define MBEDTLS_IGNORE_RETURN( result ) ((void) !(result)) + +/* PSA options */ +/** + * Use HMAC_DRBG with the specified hash algorithm for HMAC_DRBG for the + * PSA crypto subsystem. + * + * If this option is unset: + * - If CTR_DRBG is available, the PSA subsystem uses it rather than HMAC_DRBG. + * - Otherwise, the PSA subsystem uses HMAC_DRBG with either + * #MBEDTLS_MD_SHA512 or #MBEDTLS_MD_SHA256 based on availability and + * on unspecified heuristics. + */ +//#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_MD_SHA256 + +/** \def MBEDTLS_PSA_KEY_SLOT_COUNT + * Restrict the PSA library to supporting a maximum amount of simultaneously + * loaded keys. A loaded key is a key stored by the PSA Crypto core as a + * volatile key, or a persistent key which is loaded temporarily by the + * library as part of a crypto operation in flight. + * + * If this option is unset, the library will fall back to a default value of + * 32 keys. + */ +//#define MBEDTLS_PSA_KEY_SLOT_COUNT 32 + +/* 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 16384 + +/** \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_CID_IN_LEN_MAX + * + * The maximum length of CIDs used for incoming DTLS messages. + * + */ +//#define MBEDTLS_SSL_CID_IN_LEN_MAX 32 + +/** \def MBEDTLS_SSL_CID_OUT_LEN_MAX + * + * The maximum length of CIDs used for outgoing DTLS messages. + * + */ +//#define MBEDTLS_SSL_CID_OUT_LEN_MAX 32 + +/** \def MBEDTLS_SSL_CID_PADDING_GRANULARITY + * + * This option controls the use of record plaintext padding + * when using the Connection ID extension in DTLS 1.2. + * + * The padding will always be chosen so that the length of the + * padded plaintext is a multiple of the value of this option. + * + * Note: A value of \c 1 means that no padding will be used + * for outgoing records. + * + * Note: On systems lacking division instructions, + * a power of two should be preferred. + * + */ +//#define MBEDTLS_SSL_CID_PADDING_GRANULARITY 16 + +/** \def MBEDTLS_SSL_TLS1_3_PADDING_GRANULARITY + * + * This option controls the use of record plaintext padding + * in TLS 1.3. + * + * The padding will always be chosen so that the length of the + * padded plaintext is a multiple of the value of this option. + * + * Note: A value of \c 1 means that no padding will be used + * for outgoing records. + * + * Note: On systems lacking division instructions, + * a power of two should be preferred. + */ +//#define MBEDTLS_SSL_TLS1_3_PADDING_GRANULARITY 1 + +/** \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 * MBEDTLS_SSL_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 */ + +/** \def MBEDTLS_TLS_EXT_CID + * + * At the time of writing, the CID extension has not been assigned its + * final value. Set this configuration option to make Mbed TLS use a + * different value. + * + * A future minor revision of Mbed TLS may change the default value of + * this option to match evolving standards and usage. + */ +//#define MBEDTLS_TLS_EXT_CID 254 + +/** + * 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'). */ + +/** \} name SECTION: Module configuration options */ + +/** + * Use an PKC-accelerated method for calculating mpi_exp_mod. + */ +#define MBEDTLS_MPI_EXP_MOD_ALT + + +/* Target and application specific configurations + * + * Allow user to override any previous default. + * + */ +#if defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_CONFIG) +#include "mbedtls/config_psa.h" +#endif + +#include "mbedtls/check_config.h" + +#endif /* ELS_PKC_MBEDTLS_CONFIG_H */ diff --git a/bsp/projects/nxpvee-ui/bsp/pin_mux.c b/bsp/projects/nxpvee-ui/bsp/pin_mux.c new file mode 100644 index 0000000..c575f09 --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/pin_mux.c @@ -0,0 +1,1318 @@ +/* + * Copyright 2022-2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*********************************************************************************************************************** + * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file + * will be overwritten if the respective MCUXpresso Config Tools is used to update this file. + **********************************************************************************************************************/ + +/* clang-format off */ +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!GlobalInfo +product: Pins v14.0 +processor: MCXN947 +package_id: MCXN947VDF +mcu_data: ksdk2_0 +processor_version: 0.14.14 +pin_labels: +- {pin_num: T4, pin_signal: PIO4_7/CT_INP19, label: RST} +- {pin_num: D11, pin_signal: PIO0_12/FC1_P4/FC0_P0/CT0_MAT2/FLEXIO0_D4/ADC0_B12, label: CS} +- {pin_num: A12, pin_signal: PIO0_9/FC0_P5/CT_INP1/FLEXIO0_D1/ADC0_B9, label: WR/FLEXIO0_D1} +- {pin_num: C12, pin_signal: PIO0_8/FC0_P4/CT_INP0/FLEXIO0_D0/ADC0_B8, label: RD/FLEXIO_D0} +- {pin_num: C13, pin_signal: PIO0_7/WUU0_IN1/FC0_P3/CT_INP3/CMP2_IN1, label: D/C} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ +/* clang-format on */ + +#include "fsl_common.h" +#include "fsl_port.h" +#include "fsl_gpio.h" +#include "pin_mux.h" + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitBootPins + * Description : Calls initialization functions. + * + * END ****************************************************************************************************************/ +void BOARD_InitBootPins(void) +{ + BOARD_InitPins(); + BOARD_InitLcdPins(); + BOARD_InitEthernetPins(); +} + +/* clang-format off */ +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitPins: +- options: {callFromInitBoot: 'true', coreID: cm33_core0, enableClock: 'true'} +- pin_list: + - {pin_num: A1, peripheral: LP_FLEXCOMM4, signal: LPFLEXCOMM_P0, pin_signal: PIO1_8/WUU0_IN10/LPTMR1_ALT3/TRACE_DATA0/FC4_P0/FC5_P4/CT_INP8/SCT0_OUT2/FLEXIO0_D16/PLU_OUT0/ENET0_TXD2/I3C1_SDA/TSI0_CH17/ADC1_A8, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, passive_filter: disable, pull_value: low, input_buffer: enable, + invert_input: normal} + - {pin_num: B1, peripheral: LP_FLEXCOMM4, signal: LPFLEXCOMM_P1, pin_signal: PIO1_9/TRACE_DATA1/FC4_P1/FC5_P5/CT_INP9/SCT0_OUT3/FLEXIO0_D17/PLU_OUT1/ENET0_TXD3/I3C1_SCL/TSI0_CH18/ADC1_A9, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, passive_filter: disable, input_buffer: enable, invert_input: normal} + - {pin_num: K3, peripheral: USDHC0, signal: USDHC_CLK, pin_signal: PIO2_4/WUU0_IN17/FC9_P0/SDHC0_CLK/SCT0_OUT2/PWM1_A1/FLEXIO0_D12/FLEXSPI0_B_DATA0/SINC0_MCLK1/SAI0_RXD1, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: K1, peripheral: USDHC0, signal: USDHC_CMD, pin_signal: PIO2_5/TRIG_OUT3/FC9_P2/SDHC0_CMD/SCT0_OUT3/PWM1_B1/FLEXIO0_D13/FLEXSPI0_B_DATA1/SINC0_MBIT1/SAI0_TXD1, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: J3, peripheral: USDHC0, signal: 'USDHC_DATA, 0', pin_signal: PIO2_3/FC9_P1/SDHC0_D0/SCT0_OUT1/PWM1_B2/FLEXIO0_D11/FLEXSPI0_B_SCLK/SINC0_MBIT0/SAI0_RXD0, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: H3, peripheral: USDHC0, signal: 'USDHC_DATA, 1', pin_signal: PIO2_2/WUU0_IN16/CLKOUT/FC9_P3/SDHC0_D1/SCT0_OUT0/PWM1_A2/FLEXIO0_D10/FLEXSPI0_B_SS0_b/SINC0_MCLK0/SAI0_TXD0, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: L2, peripheral: USDHC0, signal: 'USDHC_DATA, 2', pin_signal: PIO2_7/TRIG_IN5/FC9_P5/SDHC0_D2/SCT0_OUT5/PWM1_B0/FLEXIO0_D15/FLEXSPI0_B_DATA3/SINC0_MBIT2/SAI0_TX_FS, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: K2, peripheral: USDHC0, signal: 'USDHC_DATA, 3', pin_signal: PIO2_6/TRIG_IN4/FC9_P4/SDHC0_D3/SCT0_OUT4/PWM1_A0/FLEXIO0_D14/FLEXSPI0_B_DATA2/SINC0_MCLK2/SAI0_TX_BCLK, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: H1, peripheral: GPIO2, signal: 'GPIO, 1', pin_signal: PIO2_1/TRACE_CLK/SDHC0_D4/SCT0_IN1/PWM1_B3/FLEXIO0_D9/FLEXSPI0_B_DQS/SINC0_MCLK_OUT0/SAI0_RX_FS, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ +/* clang-format on */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitPins(void) +{ +#ifdef ENABLE_AI + /* Enables the clock for PORT0 controller: Enables clock */ + CLOCK_EnableClock(kCLOCK_Port0); +#endif + + /* Enables the clock for PORT1: Enables clock */ + CLOCK_EnableClock(kCLOCK_Port1); + /* Enables the clock for PORT2: Enables clock */ + CLOCK_EnableClock(kCLOCK_Port2); + +#ifdef ENABLE_AI + const port_pin_config_t port0_2_pinB16_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* High drive strength is configured */ + kPORT_HighDriveStrength, + /* Pin is configured as SWO */ + kPORT_MuxAlt1, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT0_2 (pin B16) is configured as SWO */ + PORT_SetPinConfig(PORT0, 2U, &port0_2_pinB16_config); +#endif + + const port_pin_config_t port1_8_pinA1_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FC4_P0 */ + kPORT_MuxAlt2, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_8 (pin A1) is configured as FC4_P0 */ + PORT_SetPinConfig(PORT1, 8U, &port1_8_pinA1_config); + + const port_pin_config_t port1_9_pinB1_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FC4_P1 */ + kPORT_MuxAlt2, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_9 (pin B1) is configured as FC4_P1 */ + PORT_SetPinConfig(PORT1, 9U, &port1_9_pinB1_config); + + const port_pin_config_t port2_1_pinH1_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as PIO2_1 */ + kPORT_MuxAlt0, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_1 (pin H1) is configured as PIO2_1 */ + PORT_SetPinConfig(PORT2, 1U, &port2_1_pinH1_config); + + const port_pin_config_t port2_2_pinH3_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as SDHC0_D1 */ + kPORT_MuxAlt3, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_2 (pin H3) is configured as SDHC0_D1 */ + PORT_SetPinConfig(PORT2, 2U, &port2_2_pinH3_config); + + const port_pin_config_t port2_3_pinJ3_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as SDHC0_D0 */ + kPORT_MuxAlt3, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_3 (pin J3) is configured as SDHC0_D0 */ + PORT_SetPinConfig(PORT2, 3U, &port2_3_pinJ3_config); + + const port_pin_config_t port2_4_pinK3_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as SDHC0_CLK */ + kPORT_MuxAlt3, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_4 (pin K3) is configured as SDHC0_CLK */ + PORT_SetPinConfig(PORT2, 4U, &port2_4_pinK3_config); + + const port_pin_config_t port2_5_pinK1_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as SDHC0_CMD */ + kPORT_MuxAlt3, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_5 (pin K1) is configured as SDHC0_CMD */ + PORT_SetPinConfig(PORT2, 5U, &port2_5_pinK1_config); + + const port_pin_config_t port2_6_pinK2_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as SDHC0_D3 */ + kPORT_MuxAlt3, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_6 (pin K2) is configured as SDHC0_D3 */ + PORT_SetPinConfig(PORT2, 6U, &port2_6_pinK2_config); + + const port_pin_config_t port2_7_pinL2_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as SDHC0_D2 */ + kPORT_MuxAlt3, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_7 (pin L2) is configured as SDHC0_D2 */ + PORT_SetPinConfig(PORT2, 7U, &port2_7_pinL2_config); +} + +/* clang-format off */ +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitLcdPins: +- options: {callFromInitBoot: 'true', coreID: cm33_core0, enableClock: 'true'} +- pin_list: + - {pin_num: T4, peripheral: GPIO4, signal: 'GPIO, 7', pin_signal: PIO4_7/CT_INP19, direction: OUTPUT, slew_rate: fast, open_drain: disable, drive_strength: low, + pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: C13, peripheral: GPIO0, signal: 'GPIO, 7', pin_signal: PIO0_7/WUU0_IN1/FC0_P3/CT_INP3/CMP2_IN1, direction: OUTPUT, slew_rate: fast, open_drain: disable, + drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: D11, peripheral: GPIO0, signal: 'GPIO, 12', pin_signal: PIO0_12/FC1_P4/FC0_P0/CT0_MAT2/FLEXIO0_D4/ADC0_B12, direction: OUTPUT, slew_rate: fast, open_drain: disable, + drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: A12, peripheral: FLEXIO0, signal: 'D, 1', pin_signal: PIO0_9/FC0_P5/CT_INP1/FLEXIO0_D1/ADC0_B9, slew_rate: fast, open_drain: disable, drive_strength: low, + pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: C12, peripheral: FLEXIO0, signal: 'D, 0', pin_signal: PIO0_8/FC0_P4/CT_INP0/FLEXIO0_D0/ADC0_B8, slew_rate: fast, open_drain: disable, drive_strength: low, + pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: M2, peripheral: FLEXIO0, signal: 'D, 16', pin_signal: PIO2_8/TRACE_DATA0/SDHC0_D7/SCT0_IN2/PWM1_X0/FLEXIO0_D16/FLEXSPI0_B_DATA4/SINC0_MCLK3/SAI1_TXD0, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: M1, peripheral: FLEXIO0, signal: 'D, 17', pin_signal: PIO2_9/TRACE_DATA1/SDHC0_D6/SCT0_IN3/PWM1_X1/FLEXIO0_D17/FLEXSPI0_B_DATA5/SINC0_MBIT3/SAI1_RXD0, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: M3, peripheral: FLEXIO0, signal: 'D, 18', pin_signal: PIO2_10/TRACE_DATA2/SCT0_IN4/PWM1_X2/FLEXIO0_D18/FLEXSPI0_B_DATA6/SINC0_MCLK4/SAI1_RXD1, slew_rate: fast, + open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: N4, peripheral: FLEXIO0, signal: 'D, 19', pin_signal: PIO2_11/TRACE_DATA3/SCT0_IN5/PWM1_X3/FLEXIO0_D19/FLEXSPI0_B_DATA7/SINC0_MBIT4/SAI1_TXD1, slew_rate: fast, + open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: T6, peripheral: FLEXIO0, signal: 'D, 20', pin_signal: PIO4_12/WUU0_IN20/USB0_VBUS_DET/FC2_P0/CT4_MAT0/FLEXIO0_D20/PLU_OUT0/SINC0_MCLK0/CAN0_RXD/OPAMP0_INP0/ADC0_A5/ADC1_A5, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: T7, peripheral: FLEXIO0, signal: 'D, 21', pin_signal: PIO4_13/TRIG_IN8/FC2_P1/USB1_ID/CT4_MAT1/FLEXIO0_D21/PLU_OUT1/SINC0_MBIT0/CAN0_TXD/OPAMP0_INP1/ADC0_B5/ADC1_B5, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: N8, peripheral: FLEXIO0, signal: 'D, 22', pin_signal: PIO4_14/CT4_MAT2/FLEXIO0_D22/PLU_OUT2, slew_rate: fast, open_drain: disable, drive_strength: low, + pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: T8, peripheral: FLEXIO0, signal: 'D, 23', pin_signal: PIO4_15/WUU0_IN21/TRIG_OUT4/USB1_VBUS_DIG/CT4_MAT3/FLEXIO0_D23/PLU_OUT3/SINC0_MCLK_OUT0/CAN1_RXD/OPAMP0_OUT/ADC0_A1/CMP0_IN4P, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: R8, peripheral: FLEXIO0, signal: 'D, 24', pin_signal: PIO4_16/FC2_P2/USB1_OTG_PWR/CT3_MAT0/FLEXIO0_D24/PLU_OUT4/SINC0_MCLK1/CAN1_TXD/OPAMP1_INP0/ADC0_A6, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: R9, peripheral: FLEXIO0, signal: 'D, 25', pin_signal: PIO4_17/TRIG_IN9/FC2_P3/USB1_OTG_OC/CT3_MAT1/FLEXIO0_D25/PLU_OUT5/SINC0_MBIT1/OPAMP1_INP1/ADC0_B6, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: N10, peripheral: FLEXIO0, signal: 'D, 26', pin_signal: PIO4_18/CT3_MAT2/FLEXIO0_D26/PLU_OUT6, slew_rate: fast, open_drain: disable, drive_strength: low, + pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: R10, peripheral: FLEXIO0, signal: 'D, 27', pin_signal: PIO4_19/TRIG_OUT5/CT3_MAT3/FLEXIO0_D27/PLU_OUT7/SINC0_MCLK_OUT1/OPAMP1_OUT/ADC0_B1/CMP1_IN4P, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: T10, peripheral: FLEXIO0, signal: 'D, 28', pin_signal: PIO4_20/TRIG_IN8/FC2_P4/CT2_MAT0/FLEXIO0_D28/SINC0_MCLK2/OPAMP2_INP0/ADC1_A6, slew_rate: fast, + open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: T11, peripheral: FLEXIO0, signal: 'D, 29', pin_signal: PIO4_21/TRIG_IN9/FC2_P5/CT2_MAT1/FLEXIO0_D29/SINC0_MBIT2/OPAMP2_INP1/ADC1_B6, slew_rate: fast, + open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: T12, peripheral: FLEXIO0, signal: 'D, 30', pin_signal: PIO4_22/CT2_MAT2/FLEXIO0_D30, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, + pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: U12, peripheral: FLEXIO0, signal: 'D, 31', pin_signal: PIO4_23/TRIG_OUT5/FC2_P6/CT2_MAT3/FLEXIO0_D31/SINC0_MCLK_OUT2/OPAMP2_OUT/ADC0_A2/ADC0_B2/ADC1_B3/CMP2_IN4P, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: N7, peripheral: GPIO4, signal: 'GPIO, 6', pin_signal: PIO4_6/TRIG_OUT4/FC2_P6/CT_INP18/PLU_CLK, direction: INPUT, slew_rate: fast, open_drain: disable, + drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: P1, peripheral: LP_FLEXCOMM2, signal: LPFLEXCOMM_P0, pin_signal: PIO4_0/WUU0_IN18/TRIG_IN6/FC2_P0/CT_INP16/PLU_IN0/SINC0_MCLK3, slew_rate: fast, open_drain: disable, + drive_strength: low, pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: P2, peripheral: LP_FLEXCOMM2, signal: LPFLEXCOMM_P1, pin_signal: PIO4_1/TRIG_IN7/FC2_P1/CT_INP17/PLU_IN1, slew_rate: fast, open_drain: disable, drive_strength: low, + pull_select: up, pull_enable: enable, input_buffer: enable, invert_input: normal} + - {pin_num: F12, peripheral: GPIO0, signal: 'GPIO, 13', pin_signal: PIO0_13/FC1_P5/FC0_P1/CT0_MAT3/FLEXIO0_D5/ADC0_B13, direction: INPUT, slew_rate: fast, open_drain: disable, + drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ +/* clang-format on */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitLcdPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitLcdPins(void) +{ + /* Enables the clock for GPIO0: Enables clock */ + CLOCK_EnableClock(kCLOCK_Gpio0); + /* Enables the clock for GPIO4: Enables clock */ + CLOCK_EnableClock(kCLOCK_Gpio4); + /* Enables the clock for PORT0 controller: Enables clock */ + CLOCK_EnableClock(kCLOCK_Port0); + /* Enables the clock for PORT2: Enables clock */ + CLOCK_EnableClock(kCLOCK_Port2); + /* Enables the clock for PORT4: Enables clock */ + CLOCK_EnableClock(kCLOCK_Port4); + + gpio_pin_config_t gpio0_pinC13_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 0U + }; + /* Initialize GPIO functionality on pin PIO0_7 (pin C13) */ + GPIO_PinInit(GPIO0, 7U, &gpio0_pinC13_config); + + gpio_pin_config_t gpio0_pinD11_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 0U + }; + /* Initialize GPIO functionality on pin PIO0_12 (pin D11) */ + GPIO_PinInit(GPIO0, 12U, &gpio0_pinD11_config); + + gpio_pin_config_t gpio0_pinF12_config = { + .pinDirection = kGPIO_DigitalInput, + .outputLogic = 0U + }; + /* Initialize GPIO functionality on pin PIO0_13 (pin F12) */ + GPIO_PinInit(GPIO0, 13U, &gpio0_pinF12_config); + + gpio_pin_config_t gpio4_pinN7_config = { + .pinDirection = kGPIO_DigitalInput, + .outputLogic = 0U + }; + /* Initialize GPIO functionality on pin PIO4_6 (pin N7) */ + GPIO_PinInit(GPIO4, 6U, &gpio4_pinN7_config); + + gpio_pin_config_t gpio4_pinT4_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 0U + }; + /* Initialize GPIO functionality on pin PIO4_7 (pin T4) */ + GPIO_PinInit(GPIO4, 7U, &gpio4_pinT4_config); + + const port_pin_config_t port0_12_pinD11_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as PIO0_12 */ + kPORT_MuxAlt0, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT0_12 (pin D11) is configured as PIO0_12 */ + PORT_SetPinConfig(PORT0, 12U, &port0_12_pinD11_config); + + const port_pin_config_t port0_13_pinF12_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as PIO0_13 */ + kPORT_MuxAlt0, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT0_13 (pin F12) is configured as PIO0_13 */ + PORT_SetPinConfig(PORT0, 13U, &port0_13_pinF12_config); + + const port_pin_config_t port0_7_pinC13_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as PIO0_7 */ + kPORT_MuxAlt0, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT0_7 (pin C13) is configured as PIO0_7 */ + PORT_SetPinConfig(PORT0, 7U, &port0_7_pinC13_config); + + const port_pin_config_t port0_8_pinC12_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D0 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT0_8 (pin C12) is configured as FLEXIO0_D0 */ + PORT_SetPinConfig(PORT0, 8U, &port0_8_pinC12_config); + + const port_pin_config_t port0_9_pinA12_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D1 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT0_9 (pin A12) is configured as FLEXIO0_D1 */ + PORT_SetPinConfig(PORT0, 9U, &port0_9_pinA12_config); + + const port_pin_config_t port2_10_pinM3_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D18 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_10 (pin M3) is configured as FLEXIO0_D18 */ + PORT_SetPinConfig(PORT2, 10U, &port2_10_pinM3_config); + + const port_pin_config_t port2_11_pinN4_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D19 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_11 (pin N4) is configured as FLEXIO0_D19 */ + PORT_SetPinConfig(PORT2, 11U, &port2_11_pinN4_config); + + const port_pin_config_t port2_8_pinM2_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D16 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_8 (pin M2) is configured as FLEXIO0_D16 */ + PORT_SetPinConfig(PORT2, 8U, &port2_8_pinM2_config); + + const port_pin_config_t port2_9_pinM1_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D17 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT2_9 (pin M1) is configured as FLEXIO0_D17 */ + PORT_SetPinConfig(PORT2, 9U, &port2_9_pinM1_config); + + const port_pin_config_t port4_0_pinP1_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FC2_P0 */ + kPORT_MuxAlt2, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_0 (pin P1) is configured as FC2_P0 */ + PORT_SetPinConfig(PORT4, 0U, &port4_0_pinP1_config); + + const port_pin_config_t port4_1_pinP2_config = {/* Internal pull-up resistor is enabled */ + kPORT_PullUp, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FC2_P1 */ + kPORT_MuxAlt2, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_1 (pin P2) is configured as FC2_P1 */ + PORT_SetPinConfig(PORT4, 1U, &port4_1_pinP2_config); + + const port_pin_config_t port4_12_pinT6_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D20 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_12 (pin T6) is configured as FLEXIO0_D20 */ + PORT_SetPinConfig(PORT4, 12U, &port4_12_pinT6_config); + + const port_pin_config_t port4_13_pinT7_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D21 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_13 (pin T7) is configured as FLEXIO0_D21 */ + PORT_SetPinConfig(PORT4, 13U, &port4_13_pinT7_config); + + const port_pin_config_t port4_14_pinN8_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D22 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_14 (pin N8) is configured as FLEXIO0_D22 */ + PORT_SetPinConfig(PORT4, 14U, &port4_14_pinN8_config); + + const port_pin_config_t port4_15_pinT8_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D23 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_15 (pin T8) is configured as FLEXIO0_D23 */ + PORT_SetPinConfig(PORT4, 15U, &port4_15_pinT8_config); + + const port_pin_config_t port4_16_pinR8_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D24 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_16 (pin R8) is configured as FLEXIO0_D24 */ + PORT_SetPinConfig(PORT4, 16U, &port4_16_pinR8_config); + + const port_pin_config_t port4_17_pinR9_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D25 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_17 (pin R9) is configured as FLEXIO0_D25 */ + PORT_SetPinConfig(PORT4, 17U, &port4_17_pinR9_config); + + const port_pin_config_t port4_18_pinN10_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D26 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_18 (pin N10) is configured as FLEXIO0_D26 */ + PORT_SetPinConfig(PORT4, 18U, &port4_18_pinN10_config); + + const port_pin_config_t port4_19_pinR10_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D27 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_19 (pin R10) is configured as FLEXIO0_D27 */ + PORT_SetPinConfig(PORT4, 19U, &port4_19_pinR10_config); + + const port_pin_config_t port4_20_pinT10_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D28 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_20 (pin T10) is configured as FLEXIO0_D28 */ + PORT_SetPinConfig(PORT4, 20U, &port4_20_pinT10_config); + + const port_pin_config_t port4_21_pinT11_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D29 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_21 (pin T11) is configured as FLEXIO0_D29 */ + PORT_SetPinConfig(PORT4, 21U, &port4_21_pinT11_config); + + const port_pin_config_t port4_22_pinT12_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D30 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_22 (pin T12) is configured as FLEXIO0_D30 */ + PORT_SetPinConfig(PORT4, 22U, &port4_22_pinT12_config); + + const port_pin_config_t port4_23_pinU12_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FLEXIO0_D31 */ + kPORT_MuxAlt6, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_23 (pin U12) is configured as FLEXIO0_D31 */ + PORT_SetPinConfig(PORT4, 23U, &port4_23_pinU12_config); + + const port_pin_config_t port4_6_pinN7_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as PIO4_6 */ + kPORT_MuxAlt0, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_6 (pin N7) is configured as PIO4_6 */ + PORT_SetPinConfig(PORT4, 6U, &port4_6_pinN7_config); + + const port_pin_config_t port4_7_pinT4_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as PIO4_7 */ + kPORT_MuxAlt0, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT4_7 (pin T4) is configured as PIO4_7 */ + PORT_SetPinConfig(PORT4, 7U, &port4_7_pinT4_config); +} + +/* clang-format off */ +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitEthernetPins: +- options: {callFromInitBoot: 'true', coreID: cm33_core0, enableClock: 'true'} +- pin_list: + - {pin_num: A1, peripheral: LP_FLEXCOMM4, signal: LPFLEXCOMM_P0, pin_signal: PIO1_8/WUU0_IN10/LPTMR1_ALT3/TRACE_DATA0/FC4_P0/FC5_P4/CT_INP8/SCT0_OUT2/FLEXIO0_D16/PLU_OUT0/ENET0_TXD2/I3C1_SDA/TSI0_CH17/ADC1_A8, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, passive_filter: disable, pull_value: low, input_buffer: enable, + invert_input: normal} + - {pin_num: B1, peripheral: LP_FLEXCOMM4, signal: LPFLEXCOMM_P1, pin_signal: PIO1_9/TRACE_DATA1/FC4_P1/FC5_P5/CT_INP9/SCT0_OUT3/FLEXIO0_D17/PLU_OUT1/ENET0_TXD3/I3C1_SCL/TSI0_CH18/ADC1_A9, + slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, passive_filter: disable, input_buffer: enable, invert_input: normal} + - {pin_num: B2, peripheral: ENET0, signal: 'enet_tdata, 0', pin_signal: PIO1_6/TRIG_IN2/FC3_P6/FC5_P2/CT_INP6/SCT0_IN0/FLEXIO0_D14/ENET0_TXD0/SAI1_RX_BCLK/CAN1_TXD/TSI0_CH6/ADC0_A22, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: A2, peripheral: ENET0, signal: 'enet_tdata, 1', pin_signal: PIO1_7/WUU0_IN9/TRIG_OUT2/FC5_P3/CT_INP7/SCT0_IN1/FLEXIO0_D15/PLU_CLK/ENET0_TXD1/SAI1_RX_FS/CAN1_RXD/TSI0_CH7/ADC0_A23, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: K5, peripheral: ENET0, signal: enet_mdc, pin_signal: PIO1_20/TRIG_IN2/FC5_P4/FC4_P0/CT3_MAT2/SCT0_OUT8/FLEXIO0_D28/PLU_OUT6/ENET0_MDC/CAN1_TXD/ADC1_A20/CMP1_IN3, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: L5, peripheral: ENET0, signal: enet_mdio, pin_signal: PIO1_21/TRIG_OUT2/FC5_P5/FC4_P1/CT3_MAT3/SCT0_OUT9/FLEXIO0_D29/PLU_OUT7/ENET0_MDIO/SAI1_MCLK/CAN1_RXD/ADC1_A21/CMP2_IN3, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: B3, peripheral: ENET0, signal: enet_tx_en, pin_signal: PIO1_5/FREQME_CLK_IN1/FC3_P5/FC5_P1/CT1_MAT3/SCT0_OUT1/FLEXIO0_D13/ENET0_TXEN/SAI0_RXD1/TSI0_CH5/ADC0_A21/CMP0_IN3, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: D1, peripheral: ENET0, signal: enet_rx_dv, pin_signal: PIO1_13/TRIG_IN3/FC4_P5/FC3_P1/CT2_MAT3/SCT0_OUT5/FLEXIO0_D21/PLU_OUT3/ENET0_RXDV/CAN1_TXD/TSI0_CH22/ADC1_A13, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: D4, peripheral: ENET0, signal: 'enet_rdata, 0', pin_signal: PIO1_14/FC4_P6/FC3_P2/CT_INP10/SCT0_IN4/FLEXIO0_D22/PLU_IN2/ENET0_RXD0/TSI0_CH23/ADC1_A14, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: E4, peripheral: ENET0, signal: 'enet_rdata, 1', pin_signal: PIO1_15/WUU0_IN13/FC3_P3/CT_INP11/SCT0_IN5/FLEXIO0_D23/PLU_IN3/ENET0_RXD1/I3C1_PUR/TSI0_CH24/ADC1_A15, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + - {pin_num: A4, peripheral: ENET0, signal: enet_tx_clk, pin_signal: PIO1_4/WUU0_IN8/FREQME_CLK_IN0/FC3_P4/FC5_P0/CT1_MAT2/SCT0_OUT0/FLEXIO0_D12/ENET0_TX_CLK/SAI0_TXD1/TSI0_CH4/ADC0_A20/CMP0_IN2, + eft_interrupt: disable, slew_rate: fast, open_drain: disable, drive_strength: low, pull_select: down, pull_enable: disable, input_buffer: enable, invert_input: normal} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ +/* clang-format on */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitEthernetPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitEthernetPins(void) +{ + /* EFT detect interrupts configuration on PORT1_ */ + PORT_DisableEFTDetectInterrupts(PORT1, 0x30E0F0u); + + const port_pin_config_t port1_13_pinD1_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_RXDV */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_13 (pin D1) is configured as ENET0_RXDV */ + PORT_SetPinConfig(PORT1, 13U, &port1_13_pinD1_config); + + const port_pin_config_t port1_14_pinD4_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_RXD0 */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_14 (pin D4) is configured as ENET0_RXD0 */ + PORT_SetPinConfig(PORT1, 14U, &port1_14_pinD4_config); + + const port_pin_config_t port1_15_pinE4_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_RXD1 */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_15 (pin E4) is configured as ENET0_RXD1 */ + PORT_SetPinConfig(PORT1, 15U, &port1_15_pinE4_config); + + const port_pin_config_t port1_20_pinK5_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_MDC */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_20 (pin K5) is configured as ENET0_MDC */ + PORT_SetPinConfig(PORT1, 20U, &port1_20_pinK5_config); + + const port_pin_config_t port1_21_pinL5_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_MDIO */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_21 (pin L5) is configured as ENET0_MDIO */ + PORT_SetPinConfig(PORT1, 21U, &port1_21_pinL5_config); + + const port_pin_config_t port1_4_pinA4_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_TX_CLK */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_4 (pin A4) is configured as ENET0_TX_CLK */ + PORT_SetPinConfig(PORT1, 4U, &port1_4_pinA4_config); + + const port_pin_config_t port1_5_pinB3_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_TXEN */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_5 (pin B3) is configured as ENET0_TXEN */ + PORT_SetPinConfig(PORT1, 5U, &port1_5_pinB3_config); + + const port_pin_config_t port1_6_pinB2_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_TXD0 */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_6 (pin B2) is configured as ENET0_TXD0 */ + PORT_SetPinConfig(PORT1, 6U, &port1_6_pinB2_config); + + const port_pin_config_t port1_7_pinA2_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as ENET0_TXD1 */ + kPORT_MuxAlt9, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_7 (pin A2) is configured as ENET0_TXD1 */ + PORT_SetPinConfig(PORT1, 7U, &port1_7_pinA2_config); + + const port_pin_config_t port1_8_pinA1_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FC4_P0 */ + kPORT_MuxAlt2, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_8 (pin A1) is configured as FC4_P0 */ + PORT_SetPinConfig(PORT1, 8U, &port1_8_pinA1_config); + + const port_pin_config_t port1_9_pinB1_config = {/* Internal pull-up/down resistor is disabled */ + kPORT_PullDisable, + /* Low internal pull resistor value is selected. */ + kPORT_LowPullResistor, + /* Fast slew rate is configured */ + kPORT_FastSlewRate, + /* Passive input filter is disabled */ + kPORT_PassiveFilterDisable, + /* Open drain output is disabled */ + kPORT_OpenDrainDisable, + /* Low drive strength is configured */ + kPORT_LowDriveStrength, + /* Pin is configured as FC4_P1 */ + kPORT_MuxAlt2, + /* Digital input enabled */ + kPORT_InputBufferEnable, + /* Digital input is not inverted */ + kPORT_InputNormal, + /* Pin Control Register fields [15:0] are not locked */ + kPORT_UnlockRegister}; + /* PORT1_9 (pin B1) is configured as FC4_P1 */ + PORT_SetPinConfig(PORT1, 9U, &port1_9_pinB1_config); +} +/*********************************************************************************************************************** + * EOF + **********************************************************************************************************************/ diff --git a/bsp/projects/nxpvee-ui/bsp/pin_mux.h b/bsp/projects/nxpvee-ui/bsp/pin_mux.h new file mode 100644 index 0000000..0c6e890 --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/pin_mux.h @@ -0,0 +1,63 @@ +/* + * Copyright 2022-2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*********************************************************************************************************************** + * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file + * will be overwritten if the respective MCUXpresso Config Tools is used to update this file. + **********************************************************************************************************************/ + +#ifndef _PIN_MUX_H_ +#define _PIN_MUX_H_ + +/*! + * @addtogroup pin_mux + * @{ + */ + +/*********************************************************************************************************************** + * API + **********************************************************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Calls initialization functions. + * + */ +void BOARD_InitBootPins(void); + +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitPins(void); + +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitEthernetPins(void); + +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitLcdPins(void); + +#if defined(__cplusplus) +} +#endif + +/*! + * @} + */ +#endif /* _PIN_MUX_H_ */ + +/*********************************************************************************************************************** + * EOF + **********************************************************************************************************************/ diff --git a/bsp/projects/nxpvee-ui/bsp/simple_gfx_app_imp.c b/bsp/projects/nxpvee-ui/bsp/simple_gfx_app_imp.c new file mode 100644 index 0000000..466732a --- /dev/null +++ b/bsp/projects/nxpvee-ui/bsp/simple_gfx_app_imp.c @@ -0,0 +1,50 @@ +/* + * Copyright 2022 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#define AMP_ORANGE 30 +#define AMP_BLUE 75 +#define AMP_GREEN 30 + +int Java_com_nxp_simpleGFX_SimpleGFXNatives_get_1orange_1x(int t, int reclen, int recheight, int display_size) +{ + int centre = display_size / 2; + double sine_orange = AMP_ORANGE * cos(t * M_PI / 45.0); + return centre - reclen - reclen / 2 - AMP_ORANGE - (int)sine_orange; +} + +int Java_com_nxp_simpleGFX_SimpleGFXNatives_get_1orange_1y(int t, int reclen, int recheight, int display_size) +{ + int centre = display_size / 2; + return centre - recheight / 2; +} + +int Java_com_nxp_simpleGFX_SimpleGFXNatives_get_1blue_1x(int t, int reclen, int recheight, int display_size) +{ + int centre = display_size / 2; + return centre - reclen / 2; +} + +int Java_com_nxp_simpleGFX_SimpleGFXNatives_get_1blue_1y(int t, int reclen, int recheight, int display_size) +{ + int centre = display_size / 2; + double sine_blue = AMP_BLUE * sin(t * M_PI / 45.0); + return centre - recheight / 2 + (int)sine_blue; +} + +int Java_com_nxp_simpleGFX_SimpleGFXNatives_get_1green_1x(int t, int reclen, int recheight, int display_size) +{ + int centre = display_size / 2; + double sine_green = AMP_GREEN * cos(t * M_PI / 45.0); + return centre + reclen - reclen / 2 + AMP_GREEN + (int)sine_green; +} + +int Java_com_nxp_simpleGFX_SimpleGFXNatives_get_1green_1y(int t, int reclen, int recheight, int display_size) +{ + int centre = display_size / 2; + return centre - recheight / 2; +} diff --git a/bsp/projects/nxpvee-ui/config/inc/FreeRTOSConfig.h b/bsp/projects/nxpvee-ui/config/inc/FreeRTOSConfig.h new file mode 100644 index 0000000..164e9e0 --- /dev/null +++ b/bsp/projects/nxpvee-ui/config/inc/FreeRTOSConfig.h @@ -0,0 +1,182 @@ +/* + * FreeRTOS Kernel V10.5.1 + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configUSE_TICKLESS_IDLE 0 +#define configCPU_CLOCK_HZ (SystemCoreClock) +#define configTICK_RATE_HZ ((TickType_t)1000) +#define configMAX_PRIORITIES 18 +#define configMINIMAL_STACK_SIZE ((unsigned short)90) +#define configMAX_TASK_NAME_LEN 20 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE 8 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 + +/* Used memory allocation (heap_x.c) */ +#define configFRTOS_MEMORY_SCHEME 3 +/* Tasks.c additions (e.g. Thread Aware Debug capability) */ +#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +/* this is the basic need */ +#define configBASE_HEAP_SIZE ((size_t)(29 * 1024)) +#ifdef ENABLE_NET +#define configNET_HEAP_SIZE ((size_t)(14 * 1024)) +#else +#define configNET_HEAP_SIZE ((size_t)(0)) +#endif + +#define configTOTAL_HEAP_SIZE (configBASE_HEAP_SIZE + configNET_HEAP_SIZE) + +#define configAPPLICATION_ALLOCATED_HEAP 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Task aware debugging. */ +#define configRECORD_STACK_HIGH_ADDRESS 1 + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) + +/* Define to trap errors during development. */ +#define configASSERT(x) if(( x) == 0) {taskDISABLE_INTERRUPTS(); for (;;);} + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 0 +#define INCLUDE_xTaskGetHandle 0 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_pxTaskGetStackStart 1 + +#if defined(__ICCARM__)||defined(__CC_ARM)||defined(__GNUC__) + /* Clock manager provides in this variable system core clock frequency */ + #include + extern uint32_t SystemCoreClock; +#endif + + +#ifndef configENABLE_FPU + #define configENABLE_FPU 1 +#endif +#ifndef configENABLE_MPU + #define configENABLE_MPU 0 +#endif +#ifndef configENABLE_TRUSTZONE + #define configENABLE_TRUSTZONE 0 +#endif +#ifndef configRUN_FREERTOS_SECURE_ONLY + #define configRUN_FREERTOS_SECURE_ONLY 1 +#endif + +/* Interrupt nesting behaviour configuration. Cortex-M specific. */ +#ifdef __NVIC_PRIO_BITS +/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ +#define configPRIO_BITS __NVIC_PRIO_BITS +#else +#define configPRIO_BITS 3 /* 8 priority levels */ +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" +function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1U << (configPRIO_BITS)) - 1) + +/* The highest interrupt priority that can be used by any interrupt service +routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL +INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER +PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2 + +/* Interrupt priorities used by the kernel port layer itself. These are generic +to all Cortex-M ports, and do not rely on any particular library functions. */ +#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names. */ +#define vPortSVCHandler SVC_Handler +#define vPortPendSVHandler PendSV_Handler +#define vPortSysTickHandler SysTick_Handler + +#endif /* FREERTOS_CONFIG_H */ diff --git a/bsp/projects/nxpvee-ui/config/inc/lfs_config.h b/bsp/projects/nxpvee-ui/config/inc/lfs_config.h new file mode 100644 index 0000000..16ee7ce --- /dev/null +++ b/bsp/projects/nxpvee-ui/config/inc/lfs_config.h @@ -0,0 +1,258 @@ +/* + * lfs utility functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LFS_CONFIG_H +#define LFS_CONFIG_H + +// System includes +#include +#include +#include +#include + +#ifndef LFS_NO_MALLOC +#include +#endif +#ifndef LFS_NO_ASSERT +#include +#endif +#if !defined(LFS_NO_DEBUG) || \ + !defined(LFS_NO_WARN) || \ + !defined(LFS_NO_ERROR) || \ + defined(LFS_YES_TRACE) +#include +#endif + +#include "FreeRTOS.h" +#include "task.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @brief Start and end addresses of the LittleFS partition. + * + * The filesystem partition must not overlap the code mapped in Flash, therefore, it must be aligned + * with the RW610_flash.icf linker file, not overlapping the TEXT region: + * - define symbol m_text_start = 0x08001280; + * - define symbol m_text_end = 0x081FFFFF; + */ +#define LFS_START_ADDR 0x08200000 +#define LFS_END_ADDR 0x082FFFFF + +/** @brief Erasable block size definition. */ +#define LFS_BLOCK_SIZE 4096 + +/** @brief Number of erase cycles before LittleFS evicts metadata logs and moves the metadata to another block. */ +#define LFS_BLOCK_CYCLES 512 + +/** @brief Maximum block read size definition. */ +#define LFS_READ_SIZE 256 + +/** @brief Maximum block program size definition. */ +#define LFS_PROG_SIZE 256 + +/** @brief Minimum block cache size definition. */ +#define LFS_CACHE_SIZE 512 + +// Macros, may be replaced by system specific wrappers. Arguments to these +// macros must not have side-effects as the macros can be removed for a smaller +// code footprint + +// Logging functions +#ifndef LFS_TRACE +#ifdef LFS_YES_TRACE +#define LFS_TRACE_(fmt, ...) \ + printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") +#else +#define LFS_TRACE(...) +#endif +#endif + +#ifndef LFS_DEBUG +#ifndef LFS_NO_DEBUG +#define LFS_DEBUG_(fmt, ...) \ + printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") +#else +#define LFS_DEBUG(...) +#endif +#endif + +#ifndef LFS_WARN +#ifndef LFS_NO_WARN +#define LFS_WARN_(fmt, ...) \ + printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") +#else +#define LFS_WARN(...) +#endif +#endif + +#ifndef LFS_ERROR +#ifndef LFS_NO_ERROR +#define LFS_ERROR_(fmt, ...) \ + printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") +#else +#define LFS_ERROR(...) +#endif +#endif + +// Runtime assertions +#ifndef LFS_ASSERT +#ifndef LFS_NO_ASSERT +#define LFS_ASSERT(test) assert(test) +#else +#define LFS_ASSERT(test) +#endif +#endif + + +// Builtin functions, these may be replaced by more efficient +// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more +// expensive basic C implementation for debugging purposes + +// Min/max functions for unsigned 32-bit numbers +static inline uint32_t lfs_max(uint32_t a, uint32_t b) { + return (a > b) ? a : b; +} + +static inline uint32_t lfs_min(uint32_t a, uint32_t b) { + return (a < b) ? a : b; +} + +// Align to nearest multiple of a size +static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { + return a - (a % alignment); +} + +static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { + return lfs_aligndown(a + alignment-1, alignment); +} + +// Find the smallest power of 2 greater than or equal to a +static inline uint32_t lfs_npw2(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return 32 - __builtin_clz(a-1); +#else + uint32_t r = 0; + uint32_t s; + a -= 1; + s = (a > 0xffff) << 4; a >>= s; r |= s; + s = (a > 0xff ) << 3; a >>= s; r |= s; + s = (a > 0xf ) << 2; a >>= s; r |= s; + s = (a > 0x3 ) << 1; a >>= s; r |= s; + return (r | (a >> 1)) + 1; +#endif +} + +// Count the number of trailing binary zeros in a +// lfs_ctz(0) may be undefined +static inline uint32_t lfs_ctz(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) + return __builtin_ctz(a); +#else + return lfs_npw2((a & -a) + 1) - 1; +#endif +} + +// Count the number of binary ones in a +static inline uint32_t lfs_popc(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return __builtin_popcount(a); +#else + a = a - ((a >> 1) & 0x55555555); + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); + return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +#endif +} + +// Find the sequence comparison of a and b, this is the distance +// between a and b ignoring overflow +static inline int lfs_scmp(uint32_t a, uint32_t b) { + return (int)(unsigned)(a - b); +} + +// Convert between 32-bit little-endian and native order +static inline uint32_t lfs_fromle32(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return a; +#elif !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return __builtin_bswap32(a); +#else + return (((uint8_t*)&a)[0] << 0) | + (((uint8_t*)&a)[1] << 8) | + (((uint8_t*)&a)[2] << 16) | + (((uint8_t*)&a)[3] << 24); +#endif +} + +static inline uint32_t lfs_tole32(uint32_t a) { + return lfs_fromle32(a); +} + +// Convert between 32-bit big-endian and native order +static inline uint32_t lfs_frombe32(uint32_t a) { +#if !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return __builtin_bswap32(a); +#elif !defined(LFS_NO_INTRINSICS) && ( \ + (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return a; +#else + return (((uint8_t*)&a)[0] << 24) | + (((uint8_t*)&a)[1] << 16) | + (((uint8_t*)&a)[2] << 8) | + (((uint8_t*)&a)[3] << 0); +#endif +} + +static inline uint32_t lfs_tobe32(uint32_t a) { + return lfs_frombe32(a); +} + +// Calculate CRC-32 with polynomial = 0x04c11db7 +uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); + +// Allocate memory, only used if buffers are not provided to littlefs +// Note, memory must be 64-bit aligned +static inline void *lfs_malloc(size_t size) { +#ifndef LFS_NO_MALLOC + return pvPortMalloc(size); +#else + (void)size; + return NULL; +#endif +} + +// Deallocate memory, only used if buffers are not provided to littlefs +static inline void lfs_free(void *p) { +#ifndef LFS_NO_MALLOC + vPortFree(p); +#else + (void)p; +#endif +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/bsp/projects/nxpvee-ui/config/inc/lwipopts.h b/bsp/projects/nxpvee-ui/config/inc/lwipopts.h new file mode 100644 index 0000000..b079ea9 --- /dev/null +++ b/bsp/projects/nxpvee-ui/config/inc/lwipopts.h @@ -0,0 +1,499 @@ +/** + ****************************************************************************** + * @file lwipopts.h + * This file is based on \src\include\lwip\opt.h + ****************************************************************************** + * Copyright (c) 2013-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2018, 2022-2024 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __LWIPOPTS_H__ +#define __LWIPOPTS_H__ + +#if USE_RTOS + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#define SYS_LIGHTWEIGHT_PROT 1 + +/** + * NO_SYS==0: Use RTOS + */ +#define NO_SYS 0 +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#define LWIP_NETCONN 1 +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#define LWIP_SOCKET 1 + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#define LWIP_SO_RCVTIMEO 1 + +#else +/** + * NO_SYS==1: Bare metal lwIP + */ +#define NO_SYS 1 +/** + * LWIP_NETCONN==0: Disable Netconn API (require to use api_lib.c) + */ +#define LWIP_NETCONN 0 +/** + * LWIP_SOCKET==0: Disable Socket API (require to use sockets.c) + */ +#define LWIP_SOCKET 0 + +#endif + +#define LWIP_NETIF_HOSTNAME 1 + +/* + ------------------------------------ + ---------- LOOPIF options ---------- + ------------------------------------ +*/ +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#define LWIP_NETIF_LOOPBACK 1//mandatory +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 1 + +/* ---------- Core locking ---------- */ +/* +#define LWIP_TCPIP_CORE_LOCKING 1 + +void sys_lock_tcpip_core(void); +#define LOCK_TCPIP_CORE() sys_lock_tcpip_core() + +void sys_unlock_tcpip_core(void); +#define UNLOCK_TCPIP_CORE() sys_unlock_tcpip_core() + +void sys_check_core_locking(void); +#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking() + +void sys_mark_tcpip_thread(void); +#define LWIP_MARK_TCPIP_THREAD() sys_mark_tcpip_thread() +*/ + +/* ---------- Memory options ---------- */ +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + * 4 byte alignment -> #define MEM_ALIGNMENT 4 + * 2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT 4 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE (22 * 1024) +#endif + +/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application + sends a lot of data out of ROM (or other static memory), this + should be set high. */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF 15 +#endif +/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + per active UDP "connection". */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 6 +#endif +/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP + connections. */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB 10 +#endif +/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP + connections. */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN 6 +#endif +/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP + segments. */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG 22 +#endif +/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active + timeouts. */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT 10 +#endif +/* MEMP_NUM_REASS_DATA: The number of whole IP packets + queued for reassembly. */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA 2 +#endif + +/* ---------- Pbuf options ---------- */ +/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE 5 +#endif + +/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ +/* Default value is defined in lwip\src\include\lwip\opt.h as + * LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN)*/ + +/* ---------- IP options ---------- */ +/** + * LWIP_IPV4==1: Enable IPv4 + */ +#ifndef LWIP_IPV4 +#define LWIP_IPV4 1 +#endif +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD 0 +#endif +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 1 +#endif +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG 1 +#endif +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL 255 +#endif + +/* ---------- ARP options ---------- */ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP 1 +#endif +/* ---------- TCP options ---------- */ +#ifndef LWIP_TCP +#define LWIP_TCP 1 +#endif + +#ifndef TCP_TTL +#define TCP_TTL 255 +#endif + +/* Controls if TCP should queue segments that arrive out of + order. Define to 0 if your device is low on memory. */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ 0 +#endif + +/* TCP Maximum segment size. */ +#ifndef TCP_MSS +#define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */ +#endif + +/* TCP sender buffer space (bytes). */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF (6 * TCP_MSS) // 2 +#endif + +/* TCP sender buffer space (pbufs). This must be at least = 2 * + TCP_SND_BUF/TCP_MSS for things to work. */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN (3 * TCP_SND_BUF) / TCP_MSS // 6 +#endif + +/* TCP receive window. */ +#ifndef TCP_WND +#define TCP_WND (2 * TCP_MSS) +#endif + +/* Enable backlog*/ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG 1 +#endif + +/* ---------- Network Interfaces options ---------- */ +/* Support netif api (in netifapi.c). */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API 1 +#endif + +/* ---------- ICMP options ---------- */ +#ifndef LWIP_ICMP +#define LWIP_ICMP 1 +#endif + +/* ---------- RAW options ---------- */ +#if !defined LWIP_RAW +#define LWIP_RAW 1 +#endif + +/* ---------- DHCP options ---------- */ +/* Enable DHCP module. */ +#ifndef LWIP_DHCP +#define LWIP_DHCP 1 +#endif + +/* ---------- UDP options ---------- */ +#ifndef LWIP_UDP +#define LWIP_UDP 1 +#endif +#ifndef UDP_TTL +#define UDP_TTL 255 +#endif + +/* ---------- Statistics options ---------- */ +#ifndef LWIP_STATS +#define LWIP_STATS 0 +#endif +#ifndef LWIP_PROVIDE_ERRNO +#define LWIP_PROVIDE_ERRNO 1 +#endif + +/* + -------------------------------------- + ---------- Checksum options ---------- + -------------------------------------- +*/ + +/** + * Checksum computation verification and computation enabled by default. + * If not desired, define all of these symbols as 1. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP 0 +#endif + +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP 0 +#endif + +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP 0 +#endif + +#ifndef CHECKSUM_GEN_ICMP +#define CHECKSUM_GEN_ICMP 0 +#endif + +#ifndef CHECKSUM_GEN_ICMP6 +#define CHECKSUM_GEN_ICMP6 0 +#endif + +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP 0 +#endif + +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP 0 +#endif + +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP 0 +#endif + +#ifndef CHECKSUM_CHECK_ICMP +#define CHECKSUM_CHECK_ICMP 0 +#endif + +#ifndef CHECKSUM_CHECK_ICMP6 +#define CHECKSUM_CHECK_ICMP6 0 +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE 3000 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO 3 +#endif + +/** + * DNS related options, revisit later to fine tune. + */ +#define LWIP_DNS 1 +#define DNS_TABLE_SIZE 4 // number of table entries, default 4 +#define DNS_MAX_NAME_LENGTH 256 // max. name length, default 256 +#define DNS_MAX_SERVERS 2 // number of DNS servers, default 2 +#define DNS_DOES_NAME_CHECK 1 // compare received name with given,def 0 +#define DNS_MSG_SIZE 512 +#define MDNS_MSG_SIZE 512 + +/* + ------------------------------------ + ---------- Debugging options ---------- + ------------------------------------ +*/ + +#define LWIP_DEBUG + +#ifdef LWIP_DEBUG +#define U8_F "c" +#define S8_F "c" +#define X8_F "02x" +#define U16_F "u" +#define S16_F "d" +#define X16_F "x" +#define U32_F "u" +#define S32_F "d" +#define X32_F "x" +#define SZT_F "u" +#endif + +#define LWIP_IGMP 1 + +#define TCPIP_MBOX_SIZE 32 +#define TCPIP_THREAD_STACKSIZE 1024 +#define TCPIP_THREAD_PRIO 8 + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#define DEFAULT_RAW_RECVMBOX_SIZE 12 + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#define DEFAULT_UDP_RECVMBOX_SIZE 12 + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#define DEFAULT_TCP_RECVMBOX_SIZE 12 + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#define DEFAULT_ACCEPTMBOX_SIZE 12 + +#if (LWIP_DNS || LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND) +/* When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value*/ +#include "lwip/arch.h" +u32_t lwip_rand(void); +#define LWIP_RAND() lwip_rand() +#endif + +/** + * LWIP_NETIF_EXT_STATUS_CALLBACK==1: Support an extended callback function + * for several netif related event that supports multiple subscribers. + * @see netif_ext_status_callback + */ +#define LWIP_NETIF_EXT_STATUS_CALLBACK 1 + +/** + * IP_REASS_MAX_PBUFS: Number of buffers reserved for IP fragment reassembly. + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS 4 +#endif + +/* + ------------------------------------------------ + ---------- Network Interfaces options ---------- + ------------------------------------------------ +*/ +/** + * @defgroup lwip_opts_netif NETIF + * @ingroup lwip_opts + * @{ + */ +/** + * LWIP_SINGLE_NETIF==1: use a single netif only. This is the common case for + * small real-life targets. Some code like routing etc. can be left out. + */ +#ifndef LWIP_SINGLE_NETIF +#define LWIP_SINGLE_NETIF 0 +#endif + +/* + ------------------------------------ + ---------- Socket options ---------- + ------------------------------------ +*/ +/** + * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and + * SO_SNDTIMEO processing. + */ +#define LWIP_SO_SNDTIMEO 1//mandatory + +/** + * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and + * SO_RCVTIMEO processing. + */ +#define LWIP_SO_RCVTIMEO 1//mandatory + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#define LWIP_TCP_KEEPALIVE 1//mandatory + +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + */ +#define LWIP_SO_LINGER 1//mandatory + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#define LWIP_SO_RCVBUF 1//mandatory + +/** + * SO_REUSE==1: Enable SO_REUSEADDR option. + * This option is set via menuconfig. + */ +#define SO_REUSE 1//mandatory +/** + * TCP_LISTEN_BACKLOG==1: Handle backlog connections. + */ +#define TCP_LISTEN_BACKLOG 1 +#define MEMP_NUM_NETCONN 12 +#endif /* __LWIPOPTS_H__ */ + +/*****END OF FILE****/ diff --git a/bsp/projects/nxpvee-ui/config/inc/lwippools.h b/bsp/projects/nxpvee-ui/config/inc/lwippools.h new file mode 100644 index 0000000..5850b2d --- /dev/null +++ b/bsp/projects/nxpvee-ui/config/inc/lwippools.h @@ -0,0 +1,25 @@ +/* @file lwippools.h + * + * @brief This file contains custom LwIP memory pool definitions + * + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __LWIPPOOLS_H__ +#define __LWIPPOOLS_H__ + +#ifdef MEMP_USE_CUSTOM_POOLS +/* + * We explicitly move certain large LwIP memory pools to the custom defined + * .wlan_data section in (flash) memory to avoid memory overflow in the + * m_data section (RAM). + */ +extern unsigned char __attribute__((section(".wlan_data"))) memp_memory_PBUF_POOL_base[]; +extern unsigned char __attribute__((section(".wlan_data"))) memp_memory_TCP_PCB_POOL_base[]; + +#endif /* MEMP_USE_CUSTOM_POOLS */ + +#endif /* __LWIPPOOLS_H__ */ diff --git a/bsp/projects/nxpvee-ui/config/inc/mbedtls_config.h b/bsp/projects/nxpvee-ui/config/inc/mbedtls_config.h new file mode 100644 index 0000000..1ab6bed --- /dev/null +++ b/bsp/projects/nxpvee-ui/config/inc/mbedtls_config.h @@ -0,0 +1,4389 @@ +/** + * \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 The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2017, 2021 NXP. Not a Contribution + * + * 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. + */ + +#ifndef KSDK_MBEDTLS_CONFIG_H +#define KSDK_MBEDTLS_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/**************************** KSDK ********************************************/ + +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" + +/* Enable LTC use in library if there is LTC on chip. */ +#if defined(FSL_FEATURE_SOC_LTC_COUNT) && (FSL_FEATURE_SOC_LTC_COUNT > 0) +#include "fsl_ltc.h" + +#define LTC_INSTANCE LTC0 /* LTC base register.*/ + +#if FSL_FEATURE_LTC_HAS_SHA +#define MBEDTLS_FREESCALE_LTC_SHA1 /* Enable use of LTC SHA.*/ +#define MBEDTLS_FREESCALE_LTC_SHA256 /* Enable use of LTC SHA256.*/ +#endif +#if defined(FSL_FEATURE_LTC_HAS_DES) && FSL_FEATURE_LTC_HAS_DES +#define MBEDTLS_FREESCALE_LTC_DES /* Enable use of LTC DES.*/ +#endif +#define MBEDTLS_FREESCALE_LTC_AES /* Enable use of LTC AES.*/ +#if defined(FSL_FEATURE_LTC_HAS_GCM) && FSL_FEATURE_LTC_HAS_GCM +#define MBEDTLS_FREESCALE_LTC_AES_GCM /* Enable use of LTC AES GCM.*/ +#endif +#if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA +#define MBEDTLS_FREESCALE_LTC_PKHA /* Enable use of LTC PKHA.*/ +#define FREESCALE_PKHA_INT_MAX_BYTES 256 +#endif +#endif + +/* Enable MMCAU use in library if there is MMCAU on chip. */ +#if defined(FSL_FEATURE_SOC_MMCAU_COUNT) && (FSL_FEATURE_SOC_MMCAU_COUNT > 0) +#include "fsl_mmcau.h" + +#define MBEDTLS_FREESCALE_MMCAU_MD5 /* Enable use of MMCAU MD5.*/ +#define MBEDTLS_FREESCALE_MMCAU_SHA1 /* Enable use of MMCAU SHA1.*/ +#define MBEDTLS_FREESCALE_MMCAU_SHA256 /* Enable use of MMCAU SHA256.*/ +#define MBEDTLS_FREESCALE_MMCAU_DES /* Enable use of MMCAU DES, when LTC is disabled.*/ +#define MBEDTLS_FREESCALE_MMCAU_AES /* Enable use of MMCAU AES, when LTC is disabled.*/ +#endif + +/* Enable CAU3 use in library if there is CAU3 on chip. */ +#if defined(FSL_FEATURE_SOC_CAU3_COUNT) && (FSL_FEATURE_SOC_CAU3_COUNT > 0) +#include "fsl_cau3.h" + +#define MBEDTLS_CAU3_COMPLETION_SIGNAL kCAU3_TaskDonePoll + +#define MBEDTLS_FREESCALE_CAU3_AES /* Enable use of CAU3 AES.*/ +#define MBEDTLS_FREESCALE_CAU3_DES /* Enable use of CAU3 DES.*/ +#define MBEDTLS_FREESCALE_CAU3_SHA1 /* Enable use of CAU3 SHA1.*/ +#define MBEDTLS_FREESCALE_CAU3_SHA256 /* Enable use of CAU3 SHA256.*/ +#define MBEDTLS_FREESCALE_CAU3_PKHA /* Enable use of CAU3 PKHA.*/ +#define FREESCALE_PKHA_INT_MAX_BYTES 512 + +#define MBEDTLS_FREESCALE_CAU3_CIPHER_CMAC +#endif + +/* Enable CAAM use in library if there is CAAM on chip. */ +#if defined(FSL_FEATURE_SOC_CAAM_COUNT) && (FSL_FEATURE_SOC_CAAM_COUNT > 0) && defined(CRYPTO_USE_DRIVER_CAAM) +#include "fsl_caam.h" + +#define CAAM_INSTANCE CAAM + +#define MBEDTLS_FREESCALE_CAAM_AES /* Enable use of CAAM AES.*/ +#define MBEDTLS_FREESCALE_CAAM_AES_GCM /* Enable use of CAAM AES GCM.*/ + +#define MBEDTLS_FREESCALE_CAAM_DES /* Enable use of CAAM DES.*/ + +#define MBEDTLS_FREESCALE_CAAM_SHA1 /* Enable use of CAAM SHA1.*/ +#define MBEDTLS_FREESCALE_CAAM_SHA256 /* Enable use of CAAM SHA256.*/ + +#define MBEDTLS_FREESCALE_CAAM_PKHA /* Enable use of CAAM PKHA.*/ +#define FREESCALE_PKHA_INT_MAX_BYTES 512 +#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 +#endif + +/* Enable DCP use in library if there is DCP on chip. */ +#if defined(FSL_FEATURE_SOC_DCP_COUNT) && (FSL_FEATURE_SOC_DCP_COUNT > 0) +#include "fsl_dcp.h" + +#define MBEDTLS_FREESCALE_DCP_AES /* Enable use of DCP AES.*/ +#define MBEDTLS_FREESCALE_DCP_SHA1 /* Enable use of DCP SHA1.*/ +#define MBEDTLS_FREESCALE_DCP_SHA256 /* Enable use of DCP SHA256.*/ + +#endif + +/* Enable HASHCRYPT use in library if there is HASHCRYPT on chip. */ +#if defined(FSL_FEATURE_SOC_HASHCRYPT_COUNT) && (FSL_FEATURE_SOC_HASHCRYPT_COUNT > 0) +#include "fsl_hashcrypt.h" + +#define MBEDTLS_FREESCALE_HASHCRYPT_AES /* Enable use of HASHCRYPT AES.*/ +#define MBEDTLS_CCM_ALT /* Enable use of HASHCRYPT AES CCM .*/ +/* Hashcrypt without context switch is not able to calculate SHA in parallel with AES. + * HW acceleration of SHA is disabled by default in MbedTLS integration. + * HW acceleration of SHA is enabled on chip with context switch. + */ +#if defined(FSL_FEATURE_HASHCRYPT_HAS_RELOAD_FEATURE) +#define MBEDTLS_FREESCALE_HASHCRYPT_SHA1 /* Enable use of HASHCRYPT SHA1.*/ +#define MBEDTLS_FREESCALE_HASHCRYPT_SHA256 /* Enable use of HASHCRYPT SHA256.*/ +#endif +#endif + +#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA) || defined(MBEDTLS_FREESCALE_CAAM_PKHA) +/* + * This FREESCALE_PKHA_LONG_OPERANDS_ENABLE macro can be defined. + * In such a case both software and hardware algorithm for TFM is linked in. + * The decision for which algorithm is used is determined at runtime + * from size of inputs. If inputs and result can fit into FREESCALE_PKHA_INT_MAX_BYTES + * then we call hardware algorithm, otherwise we call software algorithm. + * + * Note that mbedTLS algorithms break modular operations unefficiently into two steps. + * First is normal operation, for example non-modular multiply, which can produce number + * with greater size than operands. Second is modular reduction. + * The implication of this is that if for example FREESCALE_PKHA_INT_MAX_BYTES is 256 (2048 bits), + * RSA-2048 still requires the FREESCALE_PKHA_LONG_OPERANDS_ENABLE macro to be defined, + * otherwise it fails at runtime. + */ +//#define FREESCALE_PKHA_LONG_OPERANDS_ENABLE +#endif + +/* Enable AES use in library if there is AES on chip. */ +#if defined(FSL_FEATURE_SOC_AES_COUNT) && (FSL_FEATURE_SOC_AES_COUNT > 0) +#include "fsl_aes.h" + +#define AES_INSTANCE AES0 /* AES base register.*/ +#define MBEDTLS_FREESCALE_LPC_AES /* Enable use of LPC AES.*/ +#define MBEDTLS_FREESCALE_LPC_AES_GCM /* Enable use of LPC AES GCM.*/ + +#endif + +/* Enable SHA use in library if there is SHA on chip. */ +#if defined(FSL_FEATURE_SOC_SHA_COUNT) && (FSL_FEATURE_SOC_SHA_COUNT > 0) +#include "fsl_sha.h" + +/* SHA HW accelerator does not support to compute multiple interleaved hashes, + * it doesn't support context switch. + * HW acceleration of SHA is disabled by default in MbedTLS integration. + */ +#define SHA_INSTANCE SHA0 /* SHA base register.*/ +#define MBEDTLS_FREESCALE_LPC_SHA1 /* Enable use of LPC SHA.*/ +#define MBEDTLS_FREESCALE_LPC_SHA256 /* Enable use of LPC SHA256.*/ +#endif + +/* Enable CASPER use in library if there is CASPER on chip. */ +#if defined(FSL_FEATURE_SOC_CASPER_COUNT) && (FSL_FEATURE_SOC_CASPER_COUNT > 0) +#include "fsl_casper.h" + +#define CASPER_INSTANCE CASPER /* CASPER base register.*/ +#define MBEDTLS_FREESCALE_CASPER_PKHA /* Enable use of CASPER PKHA.*/ +#define FREESCALE_PKHA_INT_MAX_BYTES (512) + +#define MBEDTLS_ECP_MUL_COMB_ALT /* Alternate implementation of ecp_mul_comb() */ +#define MBEDTLS_ECP_MULADD_ALT /* Alternate implementation of mbedtls_ecp_muladd() */ +#define MBEDTLS_MCUX_CASPER_ECC /* CASPER implementation */ + +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED /* Enable ECP_DP_SECP256R1 curve */ +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED /* Enable ECP_DP_SECP384R1 curve */ +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED /* Enable ECP_DP_SECP521R1 curve */ + +#endif + +/** + * \def MBEDTLS_FREESCALE_FREERTOS_CALLOC_ALT + * + * Enable implementation for FreeRTOS's pvPortCalloc() in ksdk_mbedtls.c module. + * You can comment this macro if you provide your own alternate implementation. + * + */ +#if defined(USE_RTOS) && defined(SDK_OS_FREE_RTOS) +#define MBEDTLS_FREESCALE_FREERTOS_CALLOC_ALT +#endif + +/* Define ALT functions. */ +#define MBEDTLS_ECP_ALT + +#if defined(MBEDTLS_FREESCALE_MMCAU_DES) || defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES) || defined(MBEDTLS_FREESCALE_CAU3_DES) +#define MBEDTLS_DES_ALT +#define MBEDTLS_DES3_SETKEY_ENC_ALT +#define MBEDTLS_DES3_SETKEY_DEC_ALT +#define MBEDTLS_DES3_CRYPT_ECB_ALT +#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_MMCAU_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES) +#define MBEDTLS_DES_SETKEY_ENC_ALT +#define MBEDTLS_DES_SETKEY_DEC_ALT +#define MBEDTLS_DES_CRYPT_ECB_ALT +#endif +#endif +#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES) +#define MBEDTLS_DES_CRYPT_CBC_ALT +#define MBEDTLS_DES3_CRYPT_CBC_ALT +#endif +#if defined(MBEDTLS_FREESCALE_CAU3_AES) || defined(MBEDTLS_FREESCALE_DCP_AES) +#define MBEDTLS_AES_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_AES_ALT_NO_192 +#endif +#if defined(MBEDTLS_FREESCALE_DCP_AES) +#define MBEDTLS_AES_CRYPT_CBC_ALT +#define MBEDTLS_AES_ALT_NO_256 +//#define MBEDTLS_AES192_ALT_SW +//#define MBEDTLS_AES256_ALT_SW +//#define MBEDTLS_AES_CBC_ALT_SW +#endif +#if defined(MBEDTLS_FREESCALE_LTC_AES) || defined(MBEDTLS_FREESCALE_MMCAU_AES) || \ + defined(MBEDTLS_FREESCALE_LPC_AES) || defined(MBEDTLS_FREESCALE_CAAM_AES) || \ + defined(MBEDTLS_FREESCALE_HASHCRYPT_AES) +#define MBEDTLS_AES_ALT +#define MBEDTLS_AES_SETKEY_ENC_ALT +#define MBEDTLS_AES_SETKEY_DEC_ALT +#define MBEDTLS_AES_ENCRYPT_ALT +#define MBEDTLS_AES_DECRYPT_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_AES) || defined(MBEDTLS_FREESCALE_CAAM_AES) || defined(MBEDTLS_FREESCALE_HASHCRYPT_AES) +#define MBEDTLS_AES_CRYPT_CBC_ALT +#define MBEDTLS_AES_CRYPT_CTR_ALT +#define MBEDTLS_CCM_CRYPT_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_AES_GCM) || defined(MBEDTLS_FREESCALE_LPC_AES_GCM) || \ + defined(MBEDTLS_FREESCALE_CAAM_AES_GCM) +#define MBEDTLS_GCM_CRYPT_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA) || defined(MBEDTLS_FREESCALE_CAAM_PKHA) +#define MBEDTLS_MPI_ADD_ABS_ALT +#define MBEDTLS_MPI_SUB_ABS_ALT +#define MBEDTLS_MPI_MUL_MPI_ALT +#define MBEDTLS_MPI_MOD_MPI_ALT +#define MBEDTLS_MPI_EXP_MOD_ALT +#define MBEDTLS_MPI_GCD_ALT +#define MBEDTLS_MPI_INV_MOD_ALT +#define MBEDTLS_MPI_IS_PRIME_ALT +#define MBEDTLS_ECP_MUL_COMB_ALT +#define MBEDTLS_ECP_ADD_ALT +#endif +#if defined(MBEDTLS_FREESCALE_CAU3_PKHA) +#define MBEDTLS_ECP_MUL_MXZ_ALT +#endif +#if defined(MBEDTLS_FREESCALE_CASPER_PKHA) +#define MBEDTLS_RSA_PUBLIC_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_SHA1) || defined(MBEDTLS_FREESCALE_LPC_SHA1) || \ + defined(MBEDTLS_FREESCALE_CAAM_SHA1) || defined(MBEDTLS_FREESCALE_CAU3_SHA1) || defined(MBEDTLS_FREESCALE_DCP_SHA1) || \ + defined(MBEDTLS_FREESCALE_HASHCRYPT_SHA1) +#define MBEDTLS_SHA1_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_SHA256) || defined(MBEDTLS_FREESCALE_LPC_SHA256) || \ + defined(MBEDTLS_FREESCALE_CAAM_SHA256) || defined(MBEDTLS_FREESCALE_CAU3_SHA256) || defined(MBEDTLS_FREESCALE_DCP_SHA256) || \ + defined(MBEDTLS_FREESCALE_HASHCRYPT_SHA256) +#define MBEDTLS_SHA256_ALT +/* + * LPC SHA module does not support SHA-224. + * + * Since mbed TLS does not provide separate APIs for SHA-224 and SHA-256 + * and SHA-224 is not widely used, this implementation provides HW accelerated SHA-256 only + * and SHA-224 is not available at all (calls will fail). + * + * To use SHA-224 on LPC, do not define MBEDTLS_SHA256_ALT and both SHA-224 and SHA-256 will use + * original mbed TLS software implementation. + */ +#if defined(MBEDTLS_FREESCALE_LPC_SHA256) || defined(MBEDTLS_FREESCALE_DCP_SHA256) || defined(MBEDTLS_FREESCALE_HASHCRYPT_SHA256) +#define MBEDTLS_SHA256_ALT_NO_224 +#endif +#endif +#if defined(MBEDTLS_FREESCALE_MMCAU_MD5) +#define MBEDTLS_MD5_PROCESS_ALT +#endif +#if defined(MBEDTLS_FREESCALE_MMCAU_SHA1) +#define MBEDTLS_SHA1_PROCESS_ALT +#endif +#if defined(MBEDTLS_FREESCALE_MMCAU_SHA256) +#define MBEDTLS_SHA256_PROCESS_ALT +#endif +#if defined(MBEDTLS_FREESCALE_CAU3_SHA1) +#define MBEDTLS_SHA1_PROCESS_ALT +#endif +#if defined(MBEDTLS_FREESCALE_CAU3_SHA256) +#define MBEDTLS_SHA256_ALT_NO_224 +#define MBEDTLS_SHA256_PROCESS_ALT +#endif +#if defined(MBEDTLS_FREESCALE_CAU3_CIPHER_CMAC) +#define MBEDTLS_CIPHER_CMAC_ALT + +/* this macros can be used to enable or disable AES-CMAC-256 and/or TDES-CMAC with CMAC_ALT hw acceleration */ +#define MBEDTLS_CIPHER_CMAC_AES_256_ENABLED +#define MBEDTLS_CIPHER_CMAC_TDES_ENABLED +#endif +#if defined(MBEDTLS_FREESCALE_LTC_AES) +#if !defined(FSL_FEATURE_LTC_HAS_AES192) || !FSL_FEATURE_LTC_HAS_AES192 +#define MBEDTLS_AES_ALT_NO_192 +#endif +#if !defined(FSL_FEATURE_LTC_HAS_AES256) || !FSL_FEATURE_LTC_HAS_AES256 +#define MBEDTLS_AES_ALT_NO_256 +#endif +#endif +#if defined(MBEDTLS_FREESCALE_LPC_AES) +#define MBEDTLS_AES_CRYPT_CBC_ALT +#define MBEDTLS_AES_CRYPT_CFB_ALT +#define MBEDTLS_AES_CRYPT_CTR_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LPC_SHA1) +#define MBEDTLS_SHA1_PROCESS_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LPC_SHA256) +#define MBEDTLS_SHA256_PROCESS_ALT +#endif + +/* Use SHA-256 HW acceleration for MD COOKIE when SHA-224 mode is not available */ +#ifdef MBEDTLS_SHA256_ALT_NO_224 +#define FSL_MD_COOKIE_USE_SHA256 +#endif + +#if defined(USE_RTOS) && defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" + +void *pvPortCalloc(size_t num, size_t size); /*Calloc for HEAP3.*/ + +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_STD_CALLOC pvPortCalloc +#define MBEDTLS_PLATFORM_STD_FREE vPortFree + +#endif /* USE_RTOS*/ + +/* Reduce RAM usage.*/ +/* More info: https://tls.mbed.org/kb/how-to/reduce-mbedtls-memory-and-storage-footprint */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /* To reduce peak memory usage */ +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_SSL_MAX_CONTENT_LEN (1024 * 16) /* Reduce SSL frame buffer. */ +#define MBEDTLS_MPI_WINDOW_SIZE 1 +#define MBEDTLS_ECP_WINDOW_SIZE 2 +#define MBEDTLS_MPI_MAX_SIZE 512 /* Maximum number of bytes for usable MPIs. */ +#define MBEDTLS_ECP_MAX_BITS 384 /* Maximum bit size of groups */ + +/**************************** KSDK end ****************************************/ + +/** + * \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 necessarily 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_VSNPRINTF_ALT +//#define MBEDTLS_PLATFORM_NV_SEED_ALT +//#define MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions and features so that they generate a warning if + * used. Functionality 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 this functionality. + * + * 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 and features. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions and features so that they generate an error if + * used. Functionality 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 this functionality. + * + * Uncomment to get errors on using deprecated functions and features. + */ +//#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: + * 1. The function will invoke the macro MBEDTLS_PARAM_FAILED(). + * 2. If MBEDTLS_PARAM_FAILED() did not terminate the program, the function + * will immediately return. If the function returns an Mbed TLS error code, + * the error code in this case is MBEDTLS_ERR_xxx_BAD_INPUT_DATA. + * + * When defining this flag, you also need to arrange a definition for + * MBEDTLS_PARAM_FAILED(). You can do this by any of the following methods: + * - By default, the library defines MBEDTLS_PARAM_FAILED() to call a + * function mbedtls_param_failed(), but the library does not define this + * function. If you do not make any other arrangements, you must provide + * the function mbedtls_param_failed() in your application. + * See `platform_util.h` for its prototype. + * - If you enable the macro #MBEDTLS_CHECK_PARAMS_ASSERT, then the + * library defines MBEDTLS_PARAM_FAILED(\c cond) to be `assert(cond)`. + * You can still supply an alternative definition of + * MBEDTLS_PARAM_FAILED(), which may call `assert`. + * - If you define a macro MBEDTLS_PARAM_FAILED() before including `config.h` + * or you uncomment the definition of MBEDTLS_PARAM_FAILED() in `config.h`, + * the library will call the macro that you defined and will not supply + * its own version. Note that if MBEDTLS_PARAM_FAILED() calls `assert`, + * you need to enable #MBEDTLS_CHECK_PARAMS_ASSERT so that library source + * files include ``. + * + * Uncomment to enable validation of application-controlled parameters. + */ +//#define MBEDTLS_CHECK_PARAMS + +/** + * \def MBEDTLS_CHECK_PARAMS_ASSERT + * + * Allow MBEDTLS_PARAM_FAILED() to call `assert`, and make it default to + * `assert`. This macro is only used if #MBEDTLS_CHECK_PARAMS is defined. + * + * If this macro is not defined, then MBEDTLS_PARAM_FAILED() defaults to + * calling a function mbedtls_param_failed(). See the documentation of + * #MBEDTLS_CHECK_PARAMS for details. + * + * Uncomment to allow MBEDTLS_PARAM_FAILED() to call `assert`. + */ +//#define MBEDTLS_CHECK_PARAMS_ASSERT + +/* \} 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 overridden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt + * must stay untouched. + * + * \note If you use the AES_xxx_ALT macros, then it 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. + * + * \warning If both MBEDTLS_ECDSA_SIGN_ALT and MBEDTLS_ECDSA_DETERMINISTIC are + * enabled, then the deterministic ECDH signature functions pass the + * the static HMAC-DRBG as RNG to mbedtls_ecdsa_sign(). Therefore + * alternative implementations should use the RNG only for generating + * the ephemeral key and nothing else. If this is not possible, then + * MBEDTLS_ECDSA_DETERMINISTIC should be disabled and an alternative + * implementation should be provided for mbedtls_ecdsa_sign_det_ext() + * (and for mbedtls_ecdsa_sign_det() too if backward compatibility is + * desirable). + * + */ +//#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. + * + * The original implementation can in addition be removed by setting the + * MBEDTLS_ECP_NO_FALLBACK option, in which case any function for which the + * corresponding MBEDTLS_ECP__FUNCTION_NAME__ALT macro is defined will not be + * able to fallback to curves not supported by the alternative implementation. + * + * 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 set 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 + * for the operation is supported by your implementation (i.e. your + * mbedtls_internal_ecp_grp_capable() function returns 1 for this group). If the + * group is not supported by your implementation, then the original mbed TLS + * implementation of ecp_double_jac() is used instead, unless this fallback + * behaviour is disabled by setting MBEDTLS_ECP_NO_FALLBACK (in which case + * ecp_double_jac() will return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE). + * + * The function prototypes and the definition of mbedtls_ecp_group and + * mbedtls_ecp_point will not change based on MBEDTLS_ECP_INTERNAL_ALT, so your + * implementation of mbedtls_internal_ecp__function_name__ must be compatible + * with their definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +/* Required for all the functions in this section */ +//#define MBEDTLS_ECP_INTERNAL_ALT +/* Turn off software fallback for curves not supported in hardware */ +//#define MBEDTLS_ECP_NO_FALLBACK +/* 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_CHECK_RETURN_WARNING + * + * If this macro is defined, emit a compile-time warning if application code + * calls a function without checking its return value, but the return value + * should generally be checked in portable applications. + * + * This is only supported on platforms where #MBEDTLS_CHECK_RETURN is + * implemented. Otherwise this option has no effect. + * + * Uncomment to get warnings on using fallible functions without checking + * their return value. + * + * \note This feature is a work in progress. + * Warnings will be added to more functions in the future. + * + * \note A few functions are considered critical, and ignoring the return + * value of these functions will trigger a warning even if this + * macro is not defined. To completely disable return value check + * warnings, define #MBEDTLS_CHECK_RETURN with an empty expansion. + */ +//#define MBEDTLS_CHECK_RETURN_WARNING + +/** + * \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_CTR_DRBG_USE_128_BIT_KEY + * + * Uncomment this macro to use a 128-bit key in the CTR_DRBG module. + * By default, CTR_DRBG uses a 256-bit key. + */ +//#define MBEDTLS_CTR_DRBG_USE_128_BIT_KEY + +/** + * \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_REMOVE_3DES_CIPHERSUITES + * + * Remove 3DES ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on 3DES 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. + * + * A man-in-the-browser attacker can recover authentication tokens sent through + * a TLS connection using a 3DES based cipher suite (see "On the Practical + * (In-)Security of 64-bit Block Ciphers" by Karthikeyan Bhargavan and Ga�tan + * Leurent, see https://sweet32.info/SWEET32_CCS16.pdf). If this attack falls + * in your threat model or you are unsure, then you should keep this option + * enabled to remove 3DES based cipher suites. + * + * Comment this macro to keep 3DES in the default ciphersuite list. + */ +#define MBEDTLS_REMOVE_3DES_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 + */ +/* Short Weierstrass curves (supporting ECP, ECDH, ECDSA) */ +//#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +//#ifndef MBEDTLS_FREESCALE_LTC_PKHA /* PKHA suports only <=512 */ +//#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +//#endif +//#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 +/* Montgomery curves (supporting ECP) */ +//#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_NO_INTERNAL_RNG + * + * When this option is disabled, mbedtls_ecp_mul() will make use of an + * internal RNG when called with a NULL \c f_rng argument, in order to protect + * against some side-channel attacks. + * + * This protection introduces a dependency of the ECP module on one of the + * DRBG modules. For very constrained implementations that don't require this + * protection (for example, because you're only doing signature verification, + * so not manipulating any secret, or because local/physical side-channel + * attacks are outside your threat model), it might be desirable to get rid of + * that dependency. + * + * \warning Enabling this option makes some uses of ECP vulnerable to some + * side-channel attacks. Only enable it if you know that's not a problem for + * your use case. + * + * Uncomment this macro to disable some counter-measures in ECP. + */ +//#define MBEDTLS_ECP_NO_INTERNAL_RNG + +/** + * \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, MBEDTLS_ECDSA_XXX_ALT + * and MBEDTLS_ECDH_LEGACY_CONTEXT. + */ +//#define MBEDTLS_ECP_RESTARTABLE + +/** + * \def MBEDTLS_ECDH_LEGACY_CONTEXT + * + * Use a backward compatible ECDH context. + * + * Mbed TLS supports two formats for ECDH contexts (#mbedtls_ecdh_context + * defined in `ecdh.h`). For most applications, the choice of format makes + * no difference, since all library functions can work with either format, + * except that the new format is incompatible with MBEDTLS_ECP_RESTARTABLE. + + * The new format used when this option is disabled is smaller + * (56 bytes on a 32-bit platform). In future versions of the library, it + * will support alternative implementations of ECDH operations. + * The new format is incompatible with applications that access + * context fields directly and with restartable ECP operations. + * + * Define this macro if you enable MBEDTLS_ECP_RESTARTABLE or if you + * want to access ECDH context fields directly. Otherwise you should + * comment out this macro definition. + * + * This option has no effect if #MBEDTLS_ECDH_C is not enabled. + * + * \note This configuration option is experimental. Future versions of the + * library may modify the way the ECDH context layout is configured + * and may modify the layout of the new context type. + */ +//#define MBEDTLS_ECDH_LEGACY_CONTEXT + +/** + * \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, MBEDTLS_ECDSA_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_ECDSA_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_RSA_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 + +/* MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER + * + * Enable key identifiers that encode a key owner identifier. + * + * The owner of a key is identified by a value of type ::mbedtls_key_owner_id_t + * which is currently hard-coded to be int32_t. + * + * Note that this option is meant for internal use only and may be removed + * without notice. It is incompatible with MBEDTLS_USE_PSA_CRYPTO. + */ +//#define MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER + +/** + * \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_PSA_CRYPTO_BUILTIN_KEYS + * + * Enable support for platform built-in keys. If you enable this feature, + * you must implement the function mbedtls_psa_platform_get_builtin_key(). + * See the documentation of that function for more information. + * + * Built-in keys are typically derived from a hardware unique key or + * stored in a secure element. + * + * Requires: MBEDTLS_PSA_CRYPTO_C. + * + * \warning This interface is experimental and may change or be removed + * without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS + +/** \def MBEDTLS_PSA_CRYPTO_CLIENT + * + * Enable support for PSA crypto client. + * + * \note This option allows to include the code necessary for a PSA + * crypto client when the PSA crypto implementation is not included in + * the library (MBEDTLS_PSA_CRYPTO_C disabled). The code included is the + * code to set and get PSA key attributes. + * The development of PSA drivers partially relying on the library to + * fulfill the hardware gaps is another possible usage of this option. + * + * \warning This interface is experimental and may change or be removed + * without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_CLIENT + +/** \def MBEDTLS_PSA_CRYPTO_DRIVERS + * + * Enable support for the experimental PSA crypto driver interface. + * + * Requires: MBEDTLS_PSA_CRYPTO_C + * + * \warning This interface is experimental and may change or be removed + * without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_DRIVERS + +/** \def MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + * + * Make the PSA Crypto module use an external random generator provided + * by a driver, instead of Mbed TLS's entropy and DRBG modules. + * + * \note This random generator must deliver random numbers with cryptographic + * quality and high performance. It must supply unpredictable numbers + * with a uniform distribution. The implementation of this function + * is responsible for ensuring that the random generator is seeded + * with sufficient entropy. If you have a hardware TRNG which is slow + * or delivers non-uniform output, declare it as an entropy source + * with mbedtls_entropy_add_source() instead of enabling this option. + * + * If you enable this option, you must configure the type + * ::mbedtls_psa_external_random_context_t in psa/crypto_platform.h + * and define a function called mbedtls_psa_external_get_random() + * with the following prototype: + * ``` + * psa_status_t mbedtls_psa_external_get_random( + * mbedtls_psa_external_random_context_t *context, + * uint8_t *output, size_t output_size, size_t *output_length); + * ); + * ``` + * The \c context value is initialized to 0 before the first call. + * The function must fill the \c output buffer with \p output_size bytes + * of random data and set \c *output_length to \p output_size. + * + * Requires: MBEDTLS_PSA_CRYPTO_C + * + * \warning If you enable this option, code that uses the PSA cryptography + * interface will not use any of the entropy sources set up for + * the entropy module, nor the NV seed that MBEDTLS_ENTROPY_NV_SEED + * enables. + * + * \note This option is experimental and may be removed without notice. + */ +//#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + +/** + * \def MBEDTLS_PSA_CRYPTO_SPM + * + * When MBEDTLS_PSA_CRYPTO_SPM is defined, the code is built for SPM (Secure + * Partition Manager) integration which separates the code into two parts: a + * NSPE (Non-Secure Process Environment) and an SPE (Secure Process + * Environment). + * + * Module: library/psa_crypto.c + * Requires: MBEDTLS_PSA_CRYPTO_C + * + */ +//#define MBEDTLS_PSA_CRYPTO_SPM + +/** + * \def MBEDTLS_PSA_INJECT_ENTROPY + * + * Enable support for entropy injection at first boot. This feature is + * required on systems that do not have a built-in entropy source (TRNG). + * This feature is currently not supported on systems that have a built-in + * entropy source. + * + * Requires: MBEDTLS_PSA_CRYPTO_STORAGE_C, MBEDTLS_ENTROPY_NV_SEED + * + */ +//#define MBEDTLS_PSA_INJECT_ENTROPY + +/** + * \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_SHA512_SMALLER + * + * Enable an implementation of SHA-512 that has lower ROM footprint but also + * lower performance. + * + * Uncomment to enable the smaller implementation of SHA512. + */ +//#define MBEDTLS_SHA512_SMALLER + +/** + * \def MBEDTLS_SHA512_NO_SHA384 + * + * Disable the SHA-384 option of the SHA-512 module. Use this to save some + * code size on devices that don't use SHA-384. + * + * Requires: MBEDTLS_SHA512_C + * + * Uncomment to disable SHA-384 + */ +//#define MBEDTLS_SHA512_NO_SHA384 + +/** + * \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_RECORD_CHECKING + * + * Enable the function mbedtls_ssl_check_record() which can be used to check + * the validity and authenticity of an incoming record, to verify that it has + * not been seen before. These checks are performed without modifying the + * externally visible state of the SSL context. + * + * See mbedtls_ssl_check_record() for more information. + * + * Uncomment to enable support for record checking. + */ +#define MBEDTLS_SSL_RECORD_CHECKING + +/** + * \def MBEDTLS_SSL_DTLS_CONNECTION_ID + * + * Enable support for the DTLS Connection ID extension + * (version draft-ietf-tls-dtls-connection-id-05, + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05) + * which allows to identify DTLS connections across changes + * in the underlying transport. + * + * Setting this option enables the SSL APIs `mbedtls_ssl_set_cid()`, + * `mbedtls_ssl_get_peer_cid()` and `mbedtls_ssl_conf_cid()`. + * See the corresponding documentation for more information. + * + * \warning The Connection ID extension is still in draft state. + * We make no stability promises for the availability + * or the shape of the API controlled by this option. + * + * The maximum lengths of outgoing and incoming CIDs can be configured + * through the options + * - MBEDTLS_SSL_CID_OUT_LEN_MAX + * - MBEDTLS_SSL_CID_IN_LEN_MAX. + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Uncomment to enable the Connection ID extension. + */ +//#define MBEDTLS_SSL_DTLS_CONNECTION_ID + +/** + * \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_CONTEXT_SERIALIZATION + * + * Enable serialization of the TLS context structures, through use of the + * functions mbedtls_ssl_context_save() and mbedtls_ssl_context_load(). + * + * This pair of functions allows one side of a connection to serialize the + * context associated with the connection, then free or re-use that context + * while the serialized state is persisted elsewhere, and finally deserialize + * that state to a live context for resuming read/write operations on the + * connection. From a protocol perspective, the state of the connection is + * unaffected, in particular this is entirely transparent to the peer. + * + * Note: this is distinct from TLS session resumption, which is part of the + * protocol and fully visible by the peer. TLS session resumption enables + * establishing new connections associated to a saved session with shorter, + * lighter handshakes, while context serialization is a local optimization in + * handling a single, potentially long-lived connection. + * + * Enabling these APIs makes some SSL structures larger, as 64 extra bytes are + * saved after the handshake to allow for more efficient serialization, so if + * you don't need this feature you'll save RAM by disabling it. + * + * Comment to disable the context serialization APIs. + */ +#define MBEDTLS_SSL_CONTEXT_SERIALIZATION + +/** + * \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 RFC 7627: Session Hash and Extended Master Secret + * Extension. + * + * 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 RFC 7507: Fallback Signaling Cipher Suite Value (SCSV) + * for Preventing Protocol Downgrade Attacks. + * + * 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_KEEP_PEER_CERTIFICATE + * + * This option controls the availability of the API mbedtls_ssl_get_peer_cert() + * giving access to the peer's certificate after completion of the handshake. + * + * Unless you need mbedtls_ssl_peer_cert() in your application, it is + * recommended to disable this option for reduced RAM usage. + * + * \note If this option is disabled, mbedtls_ssl_get_peer_cert() is still + * defined, but always returns \c NULL. + * + * \note This option has no influence on the protection against the + * triple handshake attack. Even if it is disabled, Mbed TLS will + * still ensure that certificates do not change during renegotiation, + * for exaple by keeping a hash of the peer's certificate. + * + * Comment this macro to disable storing the peer's certificate + * after the handshake. + */ +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * \deprecated This option is deprecated and will be removed in a future + * version of Mbed TLS. + * + * 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). + * + * \deprecated This option is deprecated and will be removed in a future + * version of Mbed TLS. + * + * 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 + * + * \deprecated This option is deprecated and will be removed in a future + * version of Mbed TLS. + * + * 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_TLS1_3_EXPERIMENTAL + * + * This macro is used to selectively enable experimental parts + * of the code that contribute to the ongoing development of + * the prototype TLS 1.3 and DTLS 1.3 implementation, and provide + * no other purpose. + * + * \warning TLS 1.3 and DTLS 1.3 aren't yet supported in Mbed TLS, + * and no feature exposed through this macro is part of the + * public API. In particular, features under the control + * of this macro are experimental and don't come with any + * stability guarantees. + * + * Uncomment this macro to enable experimental and partial + * functionality specific to TLS 1.3. + */ +//#define MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + +/** + * \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_SRTP + * + * Enable support for negotiation of DTLS-SRTP (RFC 5764) + * through the use_srtp extension. + * + * \note This feature provides the minimum functionality required + * to negotiate the use of DTLS-SRTP and to allow the derivation of + * the associated SRTP packet protection key material. + * In particular, the SRTP packet protection itself, as well as the + * demultiplexing of RTP and DTLS packets at the datagram layer + * (see Section 5 of RFC 5764), are not handled by this feature. + * Instead, after successful completion of a handshake negotiating + * the use of DTLS-SRTP, the extended key exporter API + * mbedtls_ssl_conf_export_keys_ext_cb() should be used to implement + * the key exporter described in Section 4.2 of RFC 5764 and RFC 5705 + * (this is implemented in the SSL example programs). + * The resulting key should then be passed to an SRTP stack. + * + * Setting this option enables the runtime API + * mbedtls_ssl_conf_dtls_srtp_protection_profiles() + * through which the supported DTLS-SRTP protection + * profiles can be configured. You must call this API at + * runtime if you wish to negotiate the use of DTLS-SRTP. + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Uncomment this to enable support for use_srtp extension. + */ +//#define MBEDTLS_SSL_DTLS_SRTP + +/** + * \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 (maintenance 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 will 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 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_SSL_VARIABLE_BUFFER_LENGTH + * + * When this option is enabled, the SSL buffer will be resized automatically + * based on the negotiated maximum fragment length in each direction. + * + * Requires: MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + */ +//#define MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + +/** + * \def MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN + * + * Enable testing of the constant-flow nature of some sensitive functions with + * clang's MemorySanitizer. This causes some existing tests to also test + * this non-functional property of the code under test. + * + * This setting requires compiling with clang -fsanitize=memory. The test + * suites can then be run normally. + * + * \warning This macro is only used for extended testing; it is not considered + * part of the library's API, so it may change or disappear at any time. + * + * Uncomment to enable testing of the constant-flow nature of selected code. + */ +//#define MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN + +/** + * \def MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND + * + * Enable testing of the constant-flow nature of some sensitive functions with + * valgrind's memcheck tool. This causes some existing tests to also test + * this non-functional property of the code under test. + * + * This setting requires valgrind headers for building, and is only useful for + * testing if the tests suites are run with valgrind's memcheck. This can be + * done for an individual test suite with 'valgrind ./test_suite_xxx', or when + * using CMake, this can be done for all test suites with 'make memcheck'. + * + * \warning This macro is only used for extended testing; it is not considered + * part of the library's API, so it may change or disappear at any time. + * + * Uncomment to enable testing of the constant-flow nature of selected code. + */ +//#define MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND + +/** + * \def MBEDTLS_TEST_HOOKS + * + * Enable features for invasive testing such as introspection functions and + * hooks for fault injection. This enables additional unit tests. + * + * Merely enabling this feature should not change the behavior of the product. + * It only adds new code, and new branching points where the default behavior + * is the same as when this feature is disabled. + * However, this feature increases the attack surface: there is an added + * risk of vulnerabilities, and more gadgets that can make exploits easier. + * Therefore this feature must never be enabled in production. + * + * See `docs/architecture/testing/mbed-crypto-invasive-testing.md` for more + * information. + * + * Uncomment to enable invasive tests. + */ +//#define MBEDTLS_TEST_HOOKS + +/** + * \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_USE_PSA_CRYPTO + * + * Make the X.509 and TLS library use PSA for cryptographic operations, and + * enable new APIs for using keys handled by PSA Crypto. + * + * \note Development of this option is currently in progress, and parts of Mbed + * TLS's X.509 and TLS modules are not ported to PSA yet. However, these parts + * will still continue to work as usual, so enabling this option should not + * break backwards compatibility. + * + * \warning The PSA Crypto API is in beta stage. While you're welcome to + * experiment using it, incompatible API changes are still possible, and some + * parts may not have reached the same quality as the rest of Mbed TLS yet. + * + * \warning This option enables new Mbed TLS APIs that are dependent on the + * PSA Crypto API, so can't come with the same stability guarantees as the + * rest of the Mbed TLS APIs. You're welcome to experiment with them, but for + * now, access to these APIs is opt-in (via enabling the present option), in + * order to clearly differentiate them from the stable Mbed TLS APIs. + * + * Requires: MBEDTLS_PSA_CRYPTO_C. + * + * Uncomment this to enable internal use of PSA Crypto and new associated APIs. + */ +//#define MBEDTLS_USE_PSA_CRYPTO + +/** + * \def MBEDTLS_PSA_CRYPTO_CONFIG + * + * This setting allows support for cryptographic mechanisms through the PSA + * API to be configured separately from support through the mbedtls API. + * + * Uncomment this to enable use of PSA Crypto configuration settings which + * can be found in include/psa/crypto_config.h. + * + * If you enable this option and write your own configuration file, you must + * include mbedtls/config_psa.h in your configuration file. The default + * provided mbedtls/config.h contains the necessary inclusion. + * + * This feature is still experimental and is not ready for production since + * it is not completed. + */ +//#define MBEDTLS_PSA_CRYPTO_CONFIG + +/** + * \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_TRUSTED_CERTIFICATE_CALLBACK + * + * If set, this enables the X.509 API `mbedtls_x509_crt_verify_with_ca_cb()` + * and the SSL API `mbedtls_ssl_conf_ca_cb()` which allow users to configure + * the set of trusted certificates through a callback instead of a linked + * list. + * + * This is useful for example in environments where a large number of trusted + * certificates is present and storing them in a linked list isn't efficient + * enough, or when the set of trusted certificates changes frequently. + * + * See the documentation of `mbedtls_x509_crt_verify_with_ca_cb()` and + * `mbedtls_ssl_conf_ca_cb()` for more information. + * + * Uncomment to enable trusted certificate callbacks. + */ +//#define MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK + +/** + * \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 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. + * + * \note When #MBEDTLS_CMAC_ALT is active, meaning that the underlying + * implementation of the CMAC algorithm is provided by an alternate + * implementation, that alternate implementation may opt to not support + * AES-192 or 3DES as underlying block ciphers for the CMAC operation. + * + * 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 \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY above. + * + * \note To achieve a 256-bit security strength with CTR_DRBG, + * you must use AES-256 *and* use sufficient entropy. + * See ctr_drbg.h for more details. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES random number generator. + */ +#if !(defined(MBEDTLS_AES_ENCRYPT_ALT) && defined(MBEDTLS_AES_ALT_NO_256)) +#define MBEDTLS_CTR_DRBG_C +#elif defined(MBEDTLS_AES_ALT_NO_256) +/* This macros will add support for CTR_DRBG using AES-128 for crypto engines + * without AES-256 capability. */ +#define MBEDTLS_CTR_DRBG_USE_128_BIT_KEY +#define MBEDTLS_CTR_DRBG_C +#endif + +/** + * \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, + * and at least one MBEDTLS_ECP_DP_XXX_ENABLED for a + * short Weierstrass curve. + */ +#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). + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C or MBEDTLS_ARIA_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 via the pkcs11-helper library. + * + * \deprecated This option is deprecated and will be removed in a future + * version of Mbed TLS. + * + * 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_PSA_CRYPTO_C + * + * Enable the Platform Security Architecture cryptography API. + * + * \warning The PSA Crypto API is still beta status. While you're welcome to + * experiment using it, incompatible API changes are still possible, and some + * parts may not have reached the same quality as the rest of Mbed TLS yet. + * + * Module: library/psa_crypto.c + * + * Requires: either MBEDTLS_CTR_DRBG_C and MBEDTLS_ENTROPY_C, + * or MBEDTLS_HMAC_DRBG_C and MBEDTLS_ENTROPY_C, + * or MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. + * + */ +//#define MBEDTLS_PSA_CRYPTO_C + +/** + * \def MBEDTLS_PSA_CRYPTO_SE_C + * + * Enable secure element support in the Platform Security Architecture + * cryptography API. + * + * \warning This feature is not yet suitable for production. It is provided + * for API evaluation and testing purposes only. + * + * Module: library/psa_crypto_se.c + * + * Requires: MBEDTLS_PSA_CRYPTO_C, MBEDTLS_PSA_CRYPTO_STORAGE_C + * + */ +//#define MBEDTLS_PSA_CRYPTO_SE_C + +/** + * \def MBEDTLS_PSA_CRYPTO_STORAGE_C + * + * Enable the Platform Security Architecture persistent key storage. + * + * Module: library/psa_crypto_storage.c + * + * Requires: MBEDTLS_PSA_CRYPTO_C, + * either MBEDTLS_PSA_ITS_FILE_C or a native implementation of + * the PSA ITS interface + */ +//#define MBEDTLS_PSA_CRYPTO_STORAGE_C + +/** + * \def MBEDTLS_PSA_ITS_FILE_C + * + * Enable the emulation of the Platform Security Architecture + * Internal Trusted Storage (PSA ITS) over files. + * + * Module: library/psa_its_file.c + * + * Requires: MBEDTLS_FS_IO + */ +//#define MBEDTLS_PSA_ITS_FILE_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 window 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 */ + +/* 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 correctly 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 correctly zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_VSNPRINTF_MACRO vsnprintf /**< Default vsnprintf 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, the library provides + * a default definition. If the macro #MBEDTLS_CHECK_PARAMS_ASSERT + * is defined, the default definition is `assert(cond)`, + * otherwise the default definition calls a function + * mbedtls_param_failed(). This function is declared in + * `platform_util.h` for the benefit of the library, but + * 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). + * If you define this macro to call `assert`, also define + * #MBEDTLS_CHECK_PARAMS_ASSERT so that library source files + * include ``. + * + * 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 ) + +/** \def MBEDTLS_CHECK_RETURN + * + * This macro is used at the beginning of the declaration of a function + * to indicate that its return value should be checked. It should + * instruct the compiler to emit a warning or an error if the function + * is called without checking its return value. + * + * There is a default implementation for popular compilers in platform_util.h. + * You can override the default implementation by defining your own here. + * + * If the implementation here is empty, this will effectively disable the + * checking of functions' return values. + */ +//#define MBEDTLS_CHECK_RETURN __attribute__((__warn_unused_result__)) + +/** \def MBEDTLS_IGNORE_RETURN + * + * This macro requires one argument, which should be a C function call. + * If that function call would cause a #MBEDTLS_CHECK_RETURN warning, this + * warning is suppressed. + */ +//#define MBEDTLS_IGNORE_RETURN( result ) ((void) !(result)) + +/* PSA options */ +/** + * Use HMAC_DRBG with the specified hash algorithm for HMAC_DRBG for the + * PSA crypto subsystem. + * + * If this option is unset: + * - If CTR_DRBG is available, the PSA subsystem uses it rather than HMAC_DRBG. + * - Otherwise, the PSA subsystem uses HMAC_DRBG with either + * #MBEDTLS_MD_SHA512 or #MBEDTLS_MD_SHA256 based on availability and + * on unspecified heuristics. + */ +//#define MBEDTLS_PSA_HMAC_DRBG_MD_TYPE MBEDTLS_MD_SHA256 + +/** \def MBEDTLS_PSA_KEY_SLOT_COUNT + * Restrict the PSA library to supporting a maximum amount of simultaneously + * loaded keys. A loaded key is a key stored by the PSA Crypto core as a + * volatile key, or a persistent key which is loaded temporarily by the + * library as part of a crypto operation in flight. + * + * If this option is unset, the library will fall back to a default value of + * 32 keys. + */ +//#define MBEDTLS_PSA_KEY_SLOT_COUNT 32 + +/* 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 16384 + +/** \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_CID_IN_LEN_MAX + * + * The maximum length of CIDs used for incoming DTLS messages. + * + */ +//#define MBEDTLS_SSL_CID_IN_LEN_MAX 32 + +/** \def MBEDTLS_SSL_CID_OUT_LEN_MAX + * + * The maximum length of CIDs used for outgoing DTLS messages. + * + */ +//#define MBEDTLS_SSL_CID_OUT_LEN_MAX 32 + +/** \def MBEDTLS_SSL_CID_PADDING_GRANULARITY + * + * This option controls the use of record plaintext padding + * when using the Connection ID extension in DTLS 1.2. + * + * The padding will always be chosen so that the length of the + * padded plaintext is a multiple of the value of this option. + * + * Note: A value of \c 1 means that no padding will be used + * for outgoing records. + * + * Note: On systems lacking division instructions, + * a power of two should be preferred. + * + */ +//#define MBEDTLS_SSL_CID_PADDING_GRANULARITY 16 + +/** \def MBEDTLS_SSL_TLS1_3_PADDING_GRANULARITY + * + * This option controls the use of record plaintext padding + * in TLS 1.3. + * + * The padding will always be chosen so that the length of the + * padded plaintext is a multiple of the value of this option. + * + * Note: A value of \c 1 means that no padding will be used + * for outgoing records. + * + * Note: On systems lacking division instructions, + * a power of two should be preferred. + */ +//#define MBEDTLS_SSL_TLS1_3_PADDING_GRANULARITY 1 + +/** \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 * MBEDTLS_SSL_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 */ + +/** \def MBEDTLS_TLS_EXT_CID + * + * At the time of writing, the CID extension has not been assigned its + * final value. Set this configuration option to make Mbed TLS use a + * different value. + * + * A future minor revision of Mbed TLS may change the default value of + * this option to match evolving standards and usage. + */ +//#define MBEDTLS_TLS_EXT_CID 254 + +/** + * 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 + +/** + * Enable the verified implementations of ECDH primitives from Project Everest + * (currently only Curve25519). This feature changes the layout of ECDH + * contexts and therefore is a compatibility break for applications that access + * fields of a mbedtls_ecdh_context structure directly. See also + * MBEDTLS_ECDH_LEGACY_CONTEXT in include/mbedtls/ecdh.h. + */ +//#define MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED + +/* \} 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 + +#if defined(MBEDTLS_PSA_CRYPTO_CONFIG) +#include "mbedtls/config_psa.h" +#endif + +#include "mbedtls/check_config.h" + +#endif /* KSDK_MBEDTLS_CONFIG_H */ diff --git a/bsp/projects/nxpvee-ui/config/src/lfs_util.c b/bsp/projects/nxpvee-ui/config/src/lfs_util.c new file mode 100644 index 0000000..ebddd98 --- /dev/null +++ b/bsp/projects/nxpvee-ui/config/src/lfs_util.c @@ -0,0 +1,26 @@ +/* + * lfs util functions + * + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "lfs_util.h" + +// Software CRC implementation with small lookup table +uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { + static const uint32_t rtable[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, + }; + + const uint8_t *data = buffer; + + for (size_t i = 0; i < size; i++) { + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; + crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; + } + + return crc; +} diff --git a/bsp/projects/nxpvee-ui/sdk_makefile/Makefile b/bsp/projects/nxpvee-ui/sdk_makefile/Makefile new file mode 100644 index 0000000..e51dfea --- /dev/null +++ b/bsp/projects/nxpvee-ui/sdk_makefile/Makefile @@ -0,0 +1,15 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# +TARGET=nxpvee_ui +DEVICE=MCXN947 +ADDRESS=0x10000000 +FLAVOUR=debug + +ifeq ($(strip $(RELEASE)),1) + FLAVOUR=release +endif + +include ../../common/sdk_makefile/Makefile diff --git a/bsp/projects/nxpvee-ui/sdk_makefile/debug/jlink.gdb b/bsp/projects/nxpvee-ui/sdk_makefile/debug/jlink.gdb new file mode 100644 index 0000000..e87af41 --- /dev/null +++ b/bsp/projects/nxpvee-ui/sdk_makefile/debug/jlink.gdb @@ -0,0 +1,15 @@ +target extended-remote :2331 + +set print asm-demangle on +set backtrace limit 32 +break DefaultHandler +break HardFault +break main +monitor reset 2 + +load + +set language c +set $sp = *0x0 +# start the process but immediately halt the processor +stepi diff --git a/bsp/projects/nxpvee-ui/sdk_makefile/debug/jlink_gdb.sh b/bsp/projects/nxpvee-ui/sdk_makefile/debug/jlink_gdb.sh new file mode 100755 index 0000000..564bd28 --- /dev/null +++ b/bsp/projects/nxpvee-ui/sdk_makefile/debug/jlink_gdb.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# +# Copyright 2022 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# + +JLINKK_PID=$(pgrep JLinkGDBServer) +if [ "${JLINKK_PID}" == "" ] +then + JLinkGDBServer -device "${1}" -if swd -ir > /dev/null 2>&1 & +fi diff --git a/cmake/board/board.cmake b/cmake/board/board.cmake new file mode 100644 index 0000000..ae30f4c --- /dev/null +++ b/cmake/board/board.cmake @@ -0,0 +1,9 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_runner_args(jlink "--device=MCXN947_M33_0" "--reset-after-load") + +include(cmake/board/jlink.board.cmake) diff --git a/cmake/board/jlink.board.cmake b/cmake/board/jlink.board.cmake new file mode 100644 index 0000000..f2cdea5 --- /dev/null +++ b/cmake/board/jlink.board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_set_flasher_ifnset(jlink) +board_set_debugger_ifnset(jlink) +board_finalize_runner_args(jlink "--dt-flash=y") diff --git a/cmake/flash/CMakeLists.txt b/cmake/flash/CMakeLists.txt new file mode 100644 index 0000000..472c5d1 --- /dev/null +++ b/cmake/flash/CMakeLists.txt @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: Apache-2.0 + +function(runners_yaml_append content) + # Append ${content}\n to a target property which is later evaluated as a + # generator expression when writing the flash runner yaml file. + # We define this function here to have access to the `flash` target. + + set_property( + TARGET runners_yaml_props_target + APPEND_STRING + PROPERTY yaml_contents + "${content}\n" + ) +endfunction() + +function(get_runners_prop prop out_var default_value) + # Get property 'prop' from runners_yaml_props_target, storing its + # value in 'out_var'. If the property is not found (value is + # ...-NOTFOUND), 'out_var' is set to 'default_value'. + + get_target_property(out runners_yaml_props_target "${prop}") + + if("${out}" STREQUAL "out-NOTFOUND") + set("${out_var}" "${default_value}" PARENT_SCOPE) + else() + set("${out_var}" "${out}" PARENT_SCOPE) + endif() +endfunction() + +function(runners_yaml_append_config) + # Append the common configuration values to the relevant property target. + + runners_yaml_append("\n# Common runner configuration values.") + runners_yaml_append("config:") + runners_yaml_append(" board_dir: ${BOARD_DIR}") + get_runners_prop(elf_file elf "${KERNEL_ELF_NAME}") + runners_yaml_append(" # Build outputs:") + runners_yaml_append(" elf_file: ${elf}") + if(CONFIG_BUILD_OUTPUT_HEX) + get_runners_prop(hex_file hex "${KERNEL_HEX_NAME}") + else() + get_runners_prop(hex_file hex "") + endif() + if(hex) + runners_yaml_append(" hex_file: ${hex}") + endif() + #if(CONFIG_BUILD_OUTPUT_BIN) + get_runners_prop(bin_file bin "${KERNEL_BIN_NAME}") + runners_yaml_append(" bin_file: ${bin}") + #endif() + if(CONFIG_BUILD_OUTPUT_UF2) + get_runners_prop(uf2_file uf2 "${KERNEL_UF2_NAME}") + runners_yaml_append(" uf2_file: ${uf2}") + endif() + + if(CMAKE_GDB OR OPENOCD OR OPENOCD_DEFAULT_PATH) + runners_yaml_append(" # Host tools:") + endif() + #if(CMAKE_GDB) + runners_yaml_append(" gdb: ${CMAKE_GDB}") + #endif() + if(OPENOCD) + runners_yaml_append(" openocd: ${OPENOCD}") + runners_yaml_append(" openocd_search:") + if(OPENOCD_DEFAULT_PATH) + runners_yaml_append(" - ${OPENOCD_DEFAULT_PATH}") + endif() + endif() + runners_yaml_append("") +endfunction() + +# Save runner state in a YAML file, and put that YAML file's location +# in the cache. +function(create_runners_yaml) + set(runners ${ARGV}) + + set(runners_yaml "${PROJECT_BINARY_DIR}/runners.yaml") + + runners_yaml_append("# Available runners configured by board.cmake.\nrunners:") + foreach(runner ${runners}) + runners_yaml_append("- ${runner}") + endforeach() + + if(DEFINED BOARD_FLASH_RUNNER) + runners_yaml_append("\n# Default flash runner if --runner is not given.") + runners_yaml_append("flash-runner: ${BOARD_FLASH_RUNNER}") + endif() + if(DEFINED BOARD_DEBUG_RUNNER) + runners_yaml_append("\n# Default debug runner if --runner is not given.") + runners_yaml_append("debug-runner: ${BOARD_DEBUG_RUNNER}") + endif() + + # Sets up common runner configuration values. + runners_yaml_append_config() + + # Get runner-specific arguments set in the board files. + runners_yaml_append("# Runner specific arguments") + runners_yaml_append("args:") + foreach(runner ${runners}) + string(MAKE_C_IDENTIFIER ${runner} runner_id) + runners_yaml_append(" ${runner}:") + get_property(args GLOBAL PROPERTY "BOARD_RUNNER_ARGS_${runner_id}") + if(args) + # Usually, the runner has arguments. Append them to runners.yaml, + # one per line. + foreach(arg ${args}) + runners_yaml_append(" - ${arg}") + endforeach() + else() + # If the runner doesn't need any arguments, just use an empty list. + runners_yaml_append(" []\n") + endif() + endforeach() + + # Write the final contents and set its location in the cache. + file(GENERATE OUTPUT "${runners_yaml}" CONTENT + $) + set(ZEPHYR_RUNNERS_YAML "${runners_yaml}" CACHE INTERNAL + "a configuration file for the runners Python package") +endfunction() + +get_property(RUNNERS GLOBAL PROPERTY ZEPHYR_RUNNERS) +set(RUNNERS jlink) + +# Persist the runner-related state. +# +# Available runners and their arguments are configured in board.cmake +# files. +# +# Everything is marked with FORCE so that re-running CMake updates the +# configuration if the board files change. +if(RUNNERS) + create_runners_yaml(${RUNNERS}) +endif() + +#zephyr_get(WEST_DIR) +if(WEST_DIR) + set(WEST "PYTHONPATH=${WEST_DIR}/src" "${PYTHON_EXECUTABLE};${WEST_DIR}/src/west/app/main.py;--zephyr-base=${ZEPHYR_BASE} ") +endif() + +# Generate the flash, debug, debugserver, attach targets within the build +# system itself. +foreach(target flash debug debugserver attach) + if(target STREQUAL flash) + set(comment "Flashing ${BOARD}") + elseif(target STREQUAL debug) + set(comment "Debugging ${BOARD}") + elseif(target STREQUAL debugserver) + set(comment "Debugging ${BOARD}") + if(SUPPORTED_EMU_PLATFORMS) + # cmake/qemu/CMakeLists.txt will add a debugserver target for + # emulation platforms, so we don't add one here + continue() + endif() + elseif(target STREQUAL attach) + set(comment "Debugging ${BOARD}") + endif() + string(TOUPPER ${target} TARGET_UPPER) + + list(APPEND RUNNERS_DEPS ${logical_target_for_zephyr_elf}) + + # Enable verbose output, if requested. + if(CMAKE_VERBOSE_MAKEFILE) + set(RUNNER_VERBOSE "--verbose") + else() + set(RUNNER_VERBOSE) + endif() + + if(WEST) + add_custom_target(${target} + # This script will print an error message and fail if has added + # dependencies. This is done using dedicated CMake script, as + # `cmake -E {true|false}` is not available until CMake 3.16. + COMMAND ${CMAKE_COMMAND} + -DTARGET=${target} + -DDEPENDENCIES="$" + -P ${CMAKE_CURRENT_LIST_DIR}/check_runner_dependencies.cmake + COMMAND + ${CMAKE_COMMAND} -E env + ${WEST} + ${RUNNER_VERBOSE} + ${target} + WORKING_DIRECTORY + ${APPLICATION_BINARY_DIR} + COMMENT + ${comment} + USES_TERMINAL + ) + else() + add_custom_target(${target} + COMMAND ${CMAKE_COMMAND} -E echo \"West was not found in path. To support + '${CMAKE_MAKE_PROGRAM} ${target}', please create a west workspace.\" + USES_TERMINAL + ) + endif(WEST) +endforeach() diff --git a/cmake/flash/check_runner_dependencies.cmake b/cmake/flash/check_runner_dependencies.cmake new file mode 100644 index 0000000..50a0bec --- /dev/null +++ b/cmake/flash/check_runner_dependencies.cmake @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: Apache-2.0 + +# The purpose of this script is to ensure that no runners targets contains +# additional dependencies. +# +# If the target contains dependencies, an error will be printed. +# +# Arguments to the script +# +# TARGET: The target being checked. +# DEPENDENCIES: List containing dependencies on target. + +if(DEPENDENCIES) + string(REPLACE ";" " " DEPENDENCIES "${DEPENDENCIES}") + message(FATAL_ERROR + "`${TARGET}` cannot have dependencies, please remove " + "`add_dependencies(${TARGET} ${DEPENDENCIES})` in build system." + ) +endif() diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake new file mode 100644 index 0000000..4fd79b5 --- /dev/null +++ b/cmake/modules/extensions.cmake @@ -0,0 +1,4596 @@ +# SPDX-License-Identifier: Apache-2.0 + +include_guard(GLOBAL) + +#include(user_cache) + +# Dependencies on CMake modules from the CMake distribution. +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) + +######################################################## +# Table of contents +######################################################## +# 1. Zephyr-aware extensions +# 1.1. zephyr_* +# 1.2. zephyr_library_* +# 1.2.1 zephyr_interface_library_* +# 1.3. generate_inc_* +# 1.4. board_* +# 1.5. Misc. +# 2. Kconfig-aware extensions +# 2.1 Misc +# 3. CMake-generic extensions +# 3.1. *_ifdef +# 3.2. *_ifndef +# 3.3. *_option compiler compatibility checks +# 3.3.1 Toolchain integration +# 3.4. Debugging CMake +# 3.5. File system management +# 4. Devicetree extensions +# 4.1 dt_* +# 4.2. *_if_dt_node +# 4.3 zephyr_dt_* +# 5. Zephyr linker functions +# 5.1. zephyr_linker* +# 6 Function helper macros + +######################################################## +# 1. Zephyr-aware extensions +######################################################## +# 1.1. zephyr_* +# +# The following methods are for modifying the CMake library[0] called +# "zephyr". zephyr is a catch-all CMake library for source files that +# can be built purely with the include paths, defines, and other +# compiler flags that all zephyr source files use. +# [0] https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html +# +# Example usage: +# zephyr_sources( +# random_esp32.c +# utils.c +# ) +# +# Is short for: +# target_sources(zephyr PRIVATE +# ${CMAKE_CURRENT_SOURCE_DIR}/random_esp32.c +# ${CMAKE_CURRENT_SOURCE_DIR}/utils.c +# ) +# +# As a very high-level introduction here are two call graphs that are +# purposely minimalistic and incomplete. +# +# zephyr_library_cc_option() +# | +# v +# zephyr_library_compile_options() --> target_compile_options() +# +# +# zephyr_cc_option() ---> target_cc_option() +# | +# v +# zephyr_cc_option_fallback() ---> target_cc_option_fallback() +# | +# v +# zephyr_compile_options() ---> target_compile_options() +# + + +# https://cmake.org/cmake/help/latest/command/target_sources.html +function(zephyr_sources) + foreach(arg ${ARGV}) + if(IS_DIRECTORY ${arg}) + message(FATAL_ERROR "zephyr_sources() was called on a directory") + endif() + target_sources(zephyr PRIVATE ${arg}) + endforeach() +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_include_directories.html +function(zephyr_include_directories) + target_include_directories(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_include_directories.html +function(zephyr_system_include_directories) + target_include_directories(zephyr_interface SYSTEM INTERFACE ${ARGV}) +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_compile_definitions.html +function(zephyr_compile_definitions) + target_compile_definitions(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_compile_options.html +function(zephyr_compile_options) + target_compile_options(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +# https://cmake.org/cmake/help/latest/command/target_link_libraries.html +function(zephyr_link_libraries) + target_link_libraries(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +function(zephyr_libc_link_libraries) + set_property(TARGET zephyr_interface APPEND PROPERTY LIBC_LINK_LIBRARIES ${ARGV}) +endfunction() + +# See this file section 3.1. target_cc_option +function(zephyr_cc_option) + foreach(arg ${ARGV}) + target_cc_option(zephyr_interface INTERFACE ${arg}) + endforeach() +endfunction() + +function(zephyr_cc_option_fallback option1 option2) + target_cc_option_fallback(zephyr_interface INTERFACE ${option1} ${option2}) +endfunction() + +function(zephyr_ld_options) + target_ld_options(zephyr_interface INTERFACE ${ARGV}) +endfunction() + +# Getter functions for extracting build information from +# zephyr_interface. Returning lists, and strings is supported, as is +# requesting specific categories of build information (defines, +# includes, options). +# +# The naming convention follows: +# zephyr_get_${build_information}_for_lang${format}(lang x [STRIP_PREFIX]) +# Where +# the argument 'x' is written with the result +# and +# ${build_information} can be one of +# - include_directories # -I directories +# - system_include_directories # -isystem directories +# - compile_definitions # -D'efines +# - compile_options # misc. compiler flags +# and +# ${format} can be +# - the empty string '', signifying that it should be returned as a list +# - _as_string signifying that it should be returned as a string +# and +# ${lang} can be one of +# - C +# - CXX +# - ASM +# +# STRIP_PREFIX +# +# By default the result will be returned ready to be passed directly +# to a compiler, e.g. prefixed with -D, or -I, but it is possible to +# omit this prefix by specifying 'STRIP_PREFIX' . This option has no +# effect for 'compile_options'. +# +# e.g. +# zephyr_get_include_directories_for_lang(ASM x) +# writes "-Isome_dir;-Isome/other/dir" to x + +function(zephyr_get_include_directories_for_lang_as_string lang i) + zephyr_get_include_directories_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN}) + + convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) + + set(${i} ${str_of_flags} PARENT_SCOPE) +endfunction() + +function(zephyr_get_system_include_directories_for_lang_as_string lang i) + zephyr_get_system_include_directories_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN}) + + convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) + + set(${i} ${str_of_flags} PARENT_SCOPE) +endfunction() + +function(zephyr_get_compile_definitions_for_lang_as_string lang i) + zephyr_get_compile_definitions_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN}) + + convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) + + set(${i} ${str_of_flags} PARENT_SCOPE) +endfunction() + +function(zephyr_get_compile_options_for_lang_as_string lang i) + zephyr_get_compile_options_for_lang(${lang} list_of_flags DELIMITER " ") + + convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags) + + set(${i} ${str_of_flags} PARENT_SCOPE) +endfunction() + +function(zephyr_get_include_directories_for_lang lang i) + zephyr_get_parse_args(args ${ARGN}) + get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + + process_flags(${lang} flags output_list) + string(REPLACE ";" "$" genexp_output_list "${output_list}") + + if(NOT ARGN) + set(result_output_list "-I$-I>") + elseif(args_STRIP_PREFIX) + # The list has no prefix, so don't add it. + set(result_output_list ${output_list}) + elseif(args_DELIMITER) + set(result_output_list "-I$") + endif() + set(${i} ${result_output_list} PARENT_SCOPE) +endfunction() + +function(zephyr_get_system_include_directories_for_lang lang i) + zephyr_get_parse_args(args ${ARGN}) + get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) + + process_flags(${lang} flags output_list) + string(REPLACE ";" "$" genexp_output_list "${output_list}") + + set_ifndef(args_DELIMITER "$") + set(result_output_list "$<$:-isystem$>") + + set(${i} ${result_output_list} PARENT_SCOPE) +endfunction() + +function(zephyr_get_compile_definitions_for_lang lang i) + zephyr_get_parse_args(args ${ARGN}) + get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_DEFINITIONS) + + process_flags(${lang} flags output_list) + string(REPLACE ";" "$" genexp_output_list "${output_list}") + + set_ifndef(args_DELIMITER "$") + set(result_output_list "-D$") + + set(${i} ${result_output_list} PARENT_SCOPE) +endfunction() + +function(zephyr_get_compile_options_for_lang lang i) + zephyr_get_parse_args(args ${ARGN}) + get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS) + + process_flags(${lang} flags output_list) + string(REPLACE ";" "$" genexp_output_list "${output_list}") + + set_ifndef(args_DELIMITER "$") + set(result_output_list "$") + + set(${i} ${result_output_list} PARENT_SCOPE) +endfunction() + +# This function writes a dict to it's output parameter +# 'return_dict'. The dict has information about the parsed arguments, +# +# Usage: +# zephyr_get_parse_args(foo ${ARGN}) +# print(foo_STRIP_PREFIX) # foo_STRIP_PREFIX might be set to 1 +function(zephyr_get_parse_args return_dict) + foreach(x ${ARGN}) + if(DEFINED single_argument) + set(${single_argument} ${x} PARENT_SCOPE) + unset(single_argument) + else() + if(x STREQUAL STRIP_PREFIX) + set(${return_dict}_STRIP_PREFIX 1 PARENT_SCOPE) + elseif(x STREQUAL NO_SPLIT) + set(${return_dict}_NO_SPLIT 1 PARENT_SCOPE) + elseif(x STREQUAL DELIMITER) + set(single_argument ${return_dict}_DELIMITER) + endif() + endif() + endforeach() +endfunction() + +function(process_flags lang input output) + # The flags might contains compile language generator expressions that + # look like this: + # $<$:-fno-exceptions> + # $<$:$> + # + # Flags that don't specify a language like this apply to all + # languages. + # + # See COMPILE_LANGUAGE in + # https://cmake.org/cmake/help/v3.3/manual/cmake-generator-expressions.7.html + # + # To deal with this, we apply a regex to extract the flag and also + # to find out if the language matches. + # + # If this doesn't work out we might need to ban the use of + # COMPILE_LANGUAGE and instead partition C, CXX, and ASM into + # different libraries + set(languages C CXX ASM) + + set(tmp_list "") + + foreach(flag ${${input}}) + set(is_compile_lang_generator_expression 0) + foreach(l ${languages}) + if(flag MATCHES ":([^>]+)>") + set(updated_flag ${CMAKE_MATCH_1}) + set(is_compile_lang_generator_expression 1) + if(${l} STREQUAL ${lang}) + # This test will match in case there are more generator expressions in the flag. + # As example: $<$:$> + # $<$:something>> + string(REGEX MATCH "(\\\$<)[^\\\$]*(\\\$<)[^\\\$]*(\\\$<)" IGNORE_RESULT ${flag}) + if(CMAKE_MATCH_2) + # Nested generator expressions are used, just substitute `$` to `1` + string(REGEX REPLACE "\\\$" "1" updated_flag ${flag}) + endif() + list(APPEND tmp_list ${updated_flag}) + break() + endif() + endif() + endforeach() + + if(NOT is_compile_lang_generator_expression) + # SHELL is used to avoid de-duplication, but when process flags + # then this tag must be removed to return real compile/linker flags. + if(flag MATCHES "SHELL:[ ]*(.*)") + separate_arguments(flag UNIX_COMMAND ${CMAKE_MATCH_1}) + endif() + # Flags may be placed inside generator expression, therefore any flag + # which is not already a generator expression must have commas converted. + if(NOT flag MATCHES "\\\$<.*>") + string(REPLACE "," "$" flag "${flag}") + endif() + list(APPEND tmp_list ${flag}) + endif() + endforeach() + + set(${output} ${tmp_list} PARENT_SCOPE) +endfunction() + +function(convert_list_of_flags_to_string_of_flags ptr_list_of_flags string_of_flags) + # Convert the list to a string so we can do string replace + # operations on it and replace the ";" list separators with a + # whitespace so the flags are spaced out + string(REPLACE ";" " " locally_scoped_string_of_flags "${${ptr_list_of_flags}}") + + # Set the output variable in the parent scope + set(${string_of_flags} ${locally_scoped_string_of_flags} PARENT_SCOPE) +endfunction() + +macro(get_property_and_add_prefix result target property prefix) + zephyr_get_parse_args(args ${ARGN}) + + if(args_STRIP_PREFIX) + set(maybe_prefix "") + else() + set(maybe_prefix ${prefix}) + endif() + + get_property(target_property TARGET ${target} PROPERTY ${property}) + foreach(x ${target_property}) + list(APPEND ${result} ${maybe_prefix}${x}) + endforeach() +endmacro() + +# 1.2 zephyr_library_* +# +# Zephyr libraries use CMake's library concept and a set of +# assumptions about how zephyr code is organized to cut down on +# boilerplate code. +# +# A Zephyr library can be constructed by the function zephyr_library +# or zephyr_library_named. The constructors create a CMake library +# with a name accessible through the variable ZEPHYR_CURRENT_LIBRARY. +# +# The variable ZEPHYR_CURRENT_LIBRARY should seldom be needed since +# the zephyr libraries have methods that modify the libraries. These +# methods have the signature: zephyr_library_ +# +# The methods are wrappers around the CMake target_* functions. See +# https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for +# documentation on the underlying target_* functions. +# +# The methods modify the CMake target_* API to reduce boilerplate; +# PRIVATE is assumed +# The target is assumed to be ZEPHYR_CURRENT_LIBRARY +# +# When a flag that is given through the zephyr_* API conflicts with +# the zephyr_library_* API then precedence will be given to the +# zephyr_library_* API. In other words, local configuration overrides +# global configuration. + +# Constructor with a directory-inferred name +macro(zephyr_library) + zephyr_library_get_current_dir_lib_name(${ZEPHYR_BASE} lib_name) + zephyr_library_named(${lib_name}) +endmacro() + +# Determines what the current directory's lib name would be according to the +# provided base and writes it to the argument "lib_name" +macro(zephyr_library_get_current_dir_lib_name base lib_name) + # Remove the prefix (/home/sebo/zephyr/driver/serial/CMakeLists.txt => driver/serial/CMakeLists.txt) + file(RELATIVE_PATH name ${base} ${CMAKE_CURRENT_LIST_FILE}) + + # Remove the filename (driver/serial/CMakeLists.txt => driver/serial) + get_filename_component(name ${name} DIRECTORY) + + # Replace / with __ (driver/serial => driver__serial) + string(REGEX REPLACE "/" "__" name ${name}) + + # Replace : with __ (C:/zephyrproject => C____zephyrproject) + string(REGEX REPLACE ":" "__" name ${name}) + + set(${lib_name} ${name}) +endmacro() + +# Constructor with an explicitly given name. +macro(zephyr_library_named name) + # This is a macro because we need add_library() to be executed + # within the scope of the caller. + set(ZEPHYR_CURRENT_LIBRARY ${name}) + add_library(${name} STATIC "") + + zephyr_append_cmake_library(${name}) + + target_link_libraries(${name} PUBLIC zephyr_interface) +endmacro() + +# Provides amend functionality to a Zephyr library for out-of-tree usage. +# +# When called from a Zephyr module, the corresponding zephyr library defined +# within Zephyr will be looked up. +# +# Note, in order to ensure correct library when amending, the folder structure in the +# Zephyr module must resemble the structure used in Zephyr, as example: +# +# Example: to amend the zephyr library created in +# ZEPHYR_BASE/drivers/entropy/CMakeLists.txt +# add the following file: +# ZEPHYR_MODULE/drivers/entropy/CMakeLists.txt +# with content: +# zephyr_library_amend() +# zephyr_library_sources(...) +# +# It is also possible to use generator expression when amending to Zephyr +# libraries. +# +# For example, in case it is required to expose the Zephyr library's folder as +# include path then the following is possible: +# zephyr_library_amend() +# zephyr_library_include_directories($) +# +# See the CMake documentation for more target properties or generator +# expressions. +# +macro(zephyr_library_amend) + # This is a macro because we need to ensure the ZEPHYR_CURRENT_LIBRARY and + # following zephyr_library_* calls are executed within the scope of the + # caller. + if(NOT ZEPHYR_CURRENT_MODULE_DIR) + message(FATAL_ERROR "Function only available for Zephyr modules.") + endif() + + zephyr_library_get_current_dir_lib_name(${ZEPHYR_CURRENT_MODULE_DIR} lib_name) + + set(ZEPHYR_CURRENT_LIBRARY ${lib_name}) +endmacro() + +function(zephyr_link_interface interface) + target_link_libraries(${interface} INTERFACE zephyr_interface) +endfunction() + +# +# zephyr_library versions of normal CMake target_ functions +# Note, paths passed to this function must be relative in order +# to support the library relocation feature of zephyr_code_relocate +# +function(zephyr_library_sources source) + target_sources(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${source} ${ARGN}) +endfunction() + +function(zephyr_library_include_directories) + target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${ARGN}) +endfunction() + +function(zephyr_library_link_libraries item) + target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PUBLIC ${item} ${ARGN}) +endfunction() + +function(zephyr_library_compile_definitions item) + target_compile_definitions(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${item} ${ARGN}) +endfunction() + +function(zephyr_library_compile_options item) + # The compiler is relied upon for sane behaviour when flags are in + # conflict. Compilers generally give precedence to flags given late + # on the command line. So to ensure that zephyr_library_* flags are + # placed late on the command line we create a dummy interface + # library and link with it to obtain the flags. + # + # Linking with a dummy interface library will place flags later on + # the command line than the the flags from zephyr_interface because + # zephyr_interface will be the first interface library that flags + # are taken from. + + string(MD5 uniqueness "${ARGV}") + set(lib_name options_interface_lib_${uniqueness}) + + if (NOT TARGET ${lib_name}) + # Create the unique target only if it doesn't exist. + add_library( ${lib_name} INTERFACE) + target_compile_options(${lib_name} INTERFACE ${item} ${ARGN}) + endif() + + target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${lib_name}) +endfunction() + +function(zephyr_library_cc_option) + foreach(option ${ARGV}) + string(MAKE_C_IDENTIFIER check${option} check) + zephyr_check_compiler_flag(C ${option} ${check}) + + if(${${check}}) + zephyr_library_compile_options(${option}) + endif() + endforeach() +endfunction() + +# Add the existing CMake library 'library' to the global list of +# Zephyr CMake libraries. This is done automatically by the +# constructor but must be called explicitly on CMake libraries that do +# not use a zephyr library constructor. +function(zephyr_append_cmake_library library) + if(TARGET zephyr_prebuilt) + message(WARNING + "zephyr_library() or zephyr_library_named() called in Zephyr CMake " + "application mode. `${library}` will not be treated as a Zephyr library." + "To create a Zephyr library in Zephyr CMake kernel mode consider " + "creating a Zephyr module. See more here: " + "https://docs.zephyrproject.org/latest/guides/modules.html" + ) + endif() + set_property(GLOBAL APPEND PROPERTY ZEPHYR_LIBS ${library}) +endfunction() + +# Add the imported library 'library_name', located at 'library_path' to the +# global list of Zephyr CMake libraries. +function(zephyr_library_import library_name library_path) + add_library(${library_name} STATIC IMPORTED GLOBAL) + set_target_properties(${library_name} + PROPERTIES IMPORTED_LOCATION + ${library_path} + ) + zephyr_append_cmake_library(${library_name}) +endfunction() + +# Place the current zephyr library in the application memory partition. +# +# The partition argument is the name of the partition where the library shall +# be placed. +# +# Note: Ensure the given partition has been defined using +# K_APPMEM_PARTITION_DEFINE in source code. +function(zephyr_library_app_memory partition) + set_property(TARGET zephyr_property_target + APPEND PROPERTY COMPILE_OPTIONS + "-l" $ "${partition}") +endfunction() + +# Configure a Zephyr library specific property. +# +# Usage: +# zephyr_library_property( ) +# +# Current Zephyr library specific properties that are supported: +# ALLOW_EMPTY : Allow a Zephyr library to be empty. +# An empty Zephyr library will generate a CMake +# configure time warning unless `ALLOW_EMPTY` is TRUE. +function(zephyr_library_property) + set(single_args "ALLOW_EMPTY") + cmake_parse_arguments(LIB_PROP "" "${single_args}" "" ${ARGN}) + + if(LIB_PROP_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_library_property(${ARGV0} ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}") + endif() + + foreach(arg ${single_args}) + if(DEFINED LIB_PROP_${arg}) + set_property(TARGET ${ZEPHYR_CURRENT_LIBRARY} PROPERTY ${arg} ${LIB_PROP_${arg}}) + endif() + endforeach() +endfunction() + +# 1.2.1 zephyr_interface_library_* +# +# A Zephyr interface library is a thin wrapper over a CMake INTERFACE +# library. The most important responsibility of this abstraction is to +# ensure that when a user KConfig-enables a library then the header +# files of this library will be accessible to the 'app' library. +# +# This is done because when a user uses Kconfig to enable a library he +# expects to be able to include its header files and call its +# functions out-of-the box. +# +# A Zephyr interface library should be used when there exists some +# build information (include directories, defines, compiler flags, +# etc.) that should be applied to a set of Zephyr libraries and 'app' +# might be one of these libraries. +# +# Zephyr libraries must explicitly call +# zephyr_library_link_libraries() to use this build +# information. 'app' is treated as a special case for usability +# reasons; a Kconfig option (CONFIG_APP_LINK_WITH_) +# should exist for each interface_library and will determine if 'app' +# links with the interface_library. +# +# This API has a constructor like the zephyr_library API has, but it +# does not have wrappers over the other cmake target functions. +macro(zephyr_interface_library_named name) + add_library(${name} INTERFACE) + set_property(GLOBAL APPEND PROPERTY ZEPHYR_INTERFACE_LIBS ${name}) +endmacro() + +# 1.3 generate_inc_* + +# These functions are useful if there is a need to generate a file +# that can be included into the application at build time. The file +# can also be compressed automatically when embedding it. +# +# See tests/application_development/gen_inc_file for an example of +# usage. +function(generate_inc_file + source_file # The source file to be converted to hex + generated_file # The generated file + ) + add_custom_command( + OUTPUT ${generated_file} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/build/file2hex.py + ${ARGN} # Extra arguments are passed to file2hex.py + --file ${source_file} + > ${generated_file} # Does pipe redirection work on Windows? + DEPENDS ${source_file} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endfunction() + +function(generate_inc_file_for_gen_target + target # The cmake target that depends on the generated file + source_file # The source file to be converted to hex + generated_file # The generated file + gen_target # The generated file target we depend on + # Any additional arguments are passed on to file2hex.py + ) + generate_inc_file(${source_file} ${generated_file} ${ARGN}) + + # Ensure 'generated_file' is generated before 'target' by creating a + # dependency between the two targets + + add_dependencies(${target} ${gen_target}) +endfunction() + +function(generate_inc_file_for_target + target # The cmake target that depends on the generated file + source_file # The source file to be converted to hex + generated_file # The generated file + # Any additional arguments are passed on to file2hex.py + ) + # Ensure 'generated_file' is generated before 'target' by creating a + # 'custom_target' for it and setting up a dependency between the two + # targets + + # But first create a unique name for the custom target + generate_unique_target_name_from_filename(${generated_file} generated_target_name) + + add_custom_target(${generated_target_name} DEPENDS ${generated_file}) + generate_inc_file_for_gen_target(${target} ${source_file} ${generated_file} ${generated_target_name} ${ARGN}) +endfunction() + +# 1.4. board_* +# +# This section is for extensions related to Zephyr board handling. +# +# Zephyr board extensions current contains: +# - Board runners +# - Board revision + +# Zephyr board runners: +# Zephyr board runner extension functions control Zephyr's board runners +# from the build system. The Zephyr build system has targets for +# flashing and debugging supported boards. These are wrappers around a +# "runner" Python subpackage that is part of Zephyr's "west" tool. +# +# This section provides glue between CMake and the Python code that +# manages the runners. + +function(_board_check_runner_type type) # private helper + if (NOT (("${type}" STREQUAL "FLASH") OR ("${type}" STREQUAL "DEBUG"))) + message(FATAL_ERROR "invalid type ${type}; should be FLASH or DEBUG") + endif() +endfunction() + +# This function sets the runner for the board unconditionally. It's +# meant to be used from application CMakeLists.txt files. +# +# NOTE: Usually board_set_xxx_ifnset() is best in board.cmake files. +# This lets the user set the runner at cmake time, or in their +# own application's CMakeLists.txt. +# +# Usage: +# board_set_runner(FLASH pyocd) +# +# This would set the board's flash runner to "pyocd". +# +# In general, "type" is FLASH or DEBUG, and "runner" is the name of a +# runner. +function(board_set_runner type runner) + _board_check_runner_type(${type}) + if (DEFINED BOARD_${type}_RUNNER) + message(STATUS "overriding ${type} runner ${BOARD_${type}_RUNNER}; it's now ${runner}") + endif() + set(BOARD_${type}_RUNNER ${runner} PARENT_SCOPE) +endfunction() + +# This macro is like board_set_runner(), but will only make a change +# if that runner is currently not set. +# +# See also board_set_flasher_ifnset() and board_set_debugger_ifnset(). +macro(board_set_runner_ifnset type runner) + _board_check_runner_type(${type}) + # This is a macro because set_ifndef() works at parent scope. + # If this were a function, that would be this function's scope, + # which wouldn't work. + set_ifndef(BOARD_${type}_RUNNER ${runner}) +endmacro() + +# A convenience macro for board_set_runner(FLASH ${runner}). +macro(board_set_flasher runner) + board_set_runner(FLASH ${runner}) +endmacro() + +# A convenience macro for board_set_runner(DEBUG ${runner}). +macro(board_set_debugger runner) + board_set_runner(DEBUG ${runner}) +endmacro() + +# A convenience macro for board_set_runner_ifnset(FLASH ${runner}). +macro(board_set_flasher_ifnset runner) + board_set_runner_ifnset(FLASH ${runner}) +endmacro() + +# A convenience macro for board_set_runner_ifnset(DEBUG ${runner}). +macro(board_set_debugger_ifnset runner) + board_set_runner_ifnset(DEBUG ${runner}) +endmacro() + +# This function is intended for board.cmake files and application +# CMakeLists.txt files. +# +# Usage from board.cmake files: +# board_runner_args(runner "--some-arg=val1" "--another-arg=val2") +# +# The build system will then ensure the command line used to +# create the runner contains: +# --some-arg=val1 --another-arg=val2 +# +# Within application CMakeLists.txt files, ensure that all calls to +# board_runner_args() are part of a macro named app_set_runner_args(), +# like this, which is defined before including the boilerplate file: +# macro(app_set_runner_args) +# board_runner_args(runner "--some-app-setting=value") +# endmacro() +# +# The build system tests for the existence of the macro and will +# invoke it at the appropriate time if it is defined. +# +# Any explicitly provided settings given by this function override +# defaults provided by the build system. +function(board_runner_args runner) + string(MAKE_C_IDENTIFIER ${runner} runner_id) + # Note the "_EXPLICIT_" here, and see below. + set_property(GLOBAL APPEND PROPERTY BOARD_RUNNER_ARGS_EXPLICIT_${runner_id} ${ARGN}) +endfunction() + +# This function is intended for internal use by +# boards/common/runner.board.cmake files. +# +# Basic usage: +# board_finalize_runner_args(runner) +# +# This ensures the build system captures all arguments added in any +# board_runner_args() calls, and otherwise finishes registering a +# runner for use. +# +# Extended usage: +# board_runner_args(runner "--some-arg=default-value") +# +# This provides common or default values for arguments. These are +# placed before board_runner_args() calls, so they generally take +# precedence, except for arguments which can be given multiple times +# (use these with caution). +function(board_finalize_runner_args runner) + # If the application provided a macro to add additional runner + # arguments, handle them. + if(COMMAND app_set_runner_args) + app_set_runner_args() + endif() + + # Retrieve the list of explicitly set arguments. + string(MAKE_C_IDENTIFIER ${runner} runner_id) + get_property(explicit GLOBAL PROPERTY "BOARD_RUNNER_ARGS_EXPLICIT_${runner_id}") + + # Note no _EXPLICIT_ here. This property contains the final list. + set_property(GLOBAL APPEND PROPERTY BOARD_RUNNER_ARGS_${runner_id} + # Default arguments from the common runner file come first. + ${ARGN} + # Arguments explicitly given with board_runner_args() come + # next, so they take precedence over the common runner file. + ${explicit} + # Arguments given via the CMake cache come last of all. Users + # can provide variables in this way from the CMake command line. + ${BOARD_RUNNER_ARGS_${runner_id}} + ) + + # Add the finalized runner to the global property list. + set_property(GLOBAL APPEND PROPERTY ZEPHYR_RUNNERS ${runner}) +endfunction() + +function(board_set_rimage_target target) + set(RIMAGE_TARGET ${target} CACHE STRING "rimage target") + zephyr_check_cache(RIMAGE_TARGET) +endfunction() + +# Zephyr board revision: +# +# This section provides a function for revision checking. + +# Usage: +# board_check_revision(FORMAT +# [EXACT] +# [DEFAULT_REVISION ] +# [HIGHEST_REVISION ] +# ) +# +# Zephyr board extension function. +# +# This function can be used in `boards//revision.cmake` to check a user +# requested revision against available board revisions. +# +# The function will check the revision from `-DBOARD=@` that +# is provided by the user according to the arguments. +# When `EXACT` is not specified, this function will set the Zephyr build system +# variable `ACTIVE_BOARD_REVISION` with the selected revision. +# +# FORMAT : Specify the revision format. +# LETTER: Revision format is a single letter from A - Z. +# NUMBER: Revision format is a single integer number. +# MAJOR.MINOR.PATCH: Revision format is three numbers, separated by `.`, +# `x.y.z`. Trailing zeroes may be omitted on the +# command line, which means: +# 1.0.0 == 1.0 == 1 +# +# EXACT: Revision is required to be an exact match. As example, available revisions are: +# 0.1.0 and 0.3.0, and user provides 0.2.0, then an error is reported +# when `EXACT` is given. +# If `EXACT` is not provided, then closest lower revision will be selected +# as the active revision, which in the example will be `0.1.0`. +# +# DEFAULT_REVISION: Provides a default revision to use when user has not selected +# a revision number. If no default revision is provided then +# user will be printed with an error if no revision is given +# on the command line. +# +# HIGHEST_REVISION: Allows to specify highest valid revision for a board. +# This can be used to ensure that a newer board cannot be used +# with an older Zephyr. As example, if current board supports +# revisions 0.x.0-0.99.99 and 1.0.0-1.99.99, and it is expected +# that current board implementation will not work with board +# revision 2.0.0, then HIGHEST_REVISION can be set to 1.99.99, +# and user will be printed with an error if using +# `@2.0.0` or higher. +# This field is not needed when `EXACT` is used. +# +# VALID_REVISIONS: A list of valid revisions for this board. +# If this argument is not provided, then each Kconfig fragment +# of the form ``_.conf`` in the board folder +# will be used as a valid revision for the board. +# +function(board_check_revision) + set(options EXACT) + set(single_args FORMAT DEFAULT_REVISION HIGHEST_REVISION) + set(multi_args VALID_REVISIONS) + cmake_parse_arguments(BOARD_REV "${options}" "${single_args}" "${multi_args}" ${ARGN}) + + string(TOUPPER ${BOARD_REV_FORMAT} BOARD_REV_FORMAT) + + if(NOT DEFINED BOARD_REVISION) + if(DEFINED BOARD_REV_DEFAULT_REVISION) + set(BOARD_REVISION ${BOARD_REV_DEFAULT_REVISION}) + set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE) + else() + message(FATAL_ERROR "No board revision specified, Board: `${BOARD}` \ + requires a revision. Please use: `-DBOARD=${BOARD}@`") + endif() + endif() + + if(DEFINED BOARD_REV_HIGHEST_REVISION) + if(((BOARD_REV_FORMAT STREQUAL LETTER) AND + (BOARD_REVISION STRGREATER BOARD_REV_HIGHEST_REVISION)) OR + ((BOARD_REV_FORMAT STREQUAL NUMBER) AND + (BOARD_REVISION GREATER BOARD_REV_HIGHEST_REVISION)) OR + ((BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") AND + (BOARD_REVISION VERSION_GREATER BOARD_REV_HIGHEST_REVISION)) + ) + message(FATAL_ERROR "Board revision `${BOARD_REVISION}` greater than \ + highest supported revision `${BOARD_REV_HIGHEST_REVISION}`. \ + Please specify a valid board revision.") + endif() + endif() + + if(BOARD_REV_FORMAT STREQUAL LETTER) + set(revision_regex "([A-Z])") + elseif(BOARD_REV_FORMAT STREQUAL NUMBER) + set(revision_regex "([0-9]+)") + elseif(BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") + set(revision_regex "((0|[1-9][0-9]*)(\.[0-9]+)(\.[0-9]+))") + # We allow loose @ typing on command line. + # so append missing zeroes. + if(BOARD_REVISION MATCHES "((0|[1-9][0-9]*)(\.[0-9]+)?(\.[0-9]+)?)") + if(NOT CMAKE_MATCH_3) + set(BOARD_REVISION ${BOARD_REVISION}.0) + set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE) + endif() + if(NOT CMAKE_MATCH_4) + set(BOARD_REVISION ${BOARD_REVISION}.0) + set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE) + endif() + endif() + else() + message(FATAL_ERROR "Invalid format specified for \ + `board_check_revision(FORMAT )`") + endif() + + if(NOT (BOARD_REVISION MATCHES "^${revision_regex}$")) + message(FATAL_ERROR "Invalid revision format used for `${BOARD_REVISION}`. \ + Board `${BOARD}` uses revision format: ${BOARD_REV_FORMAT}.") + endif() + + if(NOT DEFINED BOARD_REV_VALID_REVISIONS) + file(GLOB revision_candidates LIST_DIRECTORIES false RELATIVE ${BOARD_DIR} + ${BOARD_DIR}/${BOARD}_*.conf + ) + string(REPLACE "." "_" underscore_revision_regex ${revision_regex}) + set(file_revision_regex "${BOARD}_${underscore_revision_regex}.conf") + foreach(candidate ${revision_candidates}) + if(${candidate} MATCHES "${file_revision_regex}") + string(REPLACE "_" "." FOUND_BOARD_REVISION ${CMAKE_MATCH_1}) + list(APPEND BOARD_REV_VALID_REVISIONS ${FOUND_BOARD_REVISION}) + endif() + endforeach() + endif() + + if(${BOARD_REVISION} IN_LIST BOARD_REV_VALID_REVISIONS) + # Found exact match. + return() + endif() + + if(NOT BOARD_REV_EXACT) + foreach(TEST_REVISION ${BOARD_REV_VALID_REVISIONS}) + if((BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") AND + (${BOARD_REVISION} VERSION_GREATER_EQUAL ${TEST_REVISION}) AND + (${TEST_REVISION} VERSION_GREATER_EQUAL "${ACTIVE_BOARD_REVISION}") + ) + set(ACTIVE_BOARD_REVISION ${TEST_REVISION}) + elseif((BOARD_REV_FORMAT STREQUAL LETTER) AND + (${BOARD_REVISION} STRGREATER ${TEST_REVISION}) AND + (${TEST_REVISION} STRGREATER "${ACTIVE_BOARD_REVISION}") + ) + set(ACTIVE_BOARD_REVISION ${TEST_REVISION}) + elseif((BOARD_REV_FORMAT STREQUAL NUMBER) AND + (${BOARD_REVISION} GREATER ${TEST_REVISION}) AND + (${TEST_REVISION} GREATER "${ACTIVE_BOARD_REVISION}") + ) + set(ACTIVE_BOARD_REVISION ${TEST_REVISION}) + endif() + endforeach() + endif() + + if(BOARD_REV_EXACT OR NOT DEFINED ACTIVE_BOARD_REVISION) + message(FATAL_ERROR "Board revision `${BOARD_REVISION}` for board \ + `${BOARD}` not found. Please specify a valid board revision.") + endif() + + set(ACTIVE_BOARD_REVISION ${ACTIVE_BOARD_REVISION} PARENT_SCOPE) +endfunction() + +# 1.5. Misc. + +# zephyr_check_compiler_flag is a part of Zephyr's toolchain +# infrastructure. It should be used when testing toolchain +# capabilities and it should normally be used in place of the +# functions: +# +# check_compiler_flag +# check_c_compiler_flag +# check_cxx_compiler_flag +# +# See check_compiler_flag() for API documentation as it has the same +# API. +# +# It is implemented as a wrapper on top of check_compiler_flag, which +# again wraps the CMake-builtin's check_c_compiler_flag and +# check_cxx_compiler_flag. +# +# It takes time to check for compatibility of flags against toolchains +# so we cache the capability test results in USER_CACHE_DIR (This +# caching comes in addition to the caching that CMake does in the +# build folder's CMakeCache.txt) +function(zephyr_check_compiler_flag lang option check) + # Check if the option is covered by any hardcoded check before doing + # an automated test. + zephyr_check_compiler_flag_hardcoded(${lang} "${option}" _${check} exists) + if(exists) + set(${check} ${_${check}} PARENT_SCOPE) + return() + endif() + + # Locate the cache directory + set_ifndef( + ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR + ${USER_CACHE_DIR}/ToolchainCapabilityDatabase + ) + + # The toolchain capability database/cache is maintained as a + # directory of files. The filenames in the directory are keys, and + # the file contents are the values in this key-value store. + + # We need to create a unique key wrt. testing the toolchain + # capability. This key must include everything that can affect the + # toolchain test. + # + # Also, to fit the key into a filename we calculate the MD5 sum of + # the key. + + # The 'cacheformat' must be bumped if a bug in the caching mechanism + # is detected and all old keys must be invalidated. + set(cacheformat 3) + + set(key_string "") + set(key_string "${key_string}${cacheformat}_") + set(key_string "${key_string}${TOOLCHAIN_SIGNATURE}_") + set(key_string "${key_string}${lang}_") + set(key_string "${key_string}${option}_") + set(key_string "${key_string}${CMAKE_REQUIRED_FLAGS}_") + + string(MD5 key "${key_string}") + + # Check the cache + set(key_path ${ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR}/${key}) + if(EXISTS ${key_path}) + file(READ + ${key_path} # File to be read + key_value # Output variable + LIMIT 1 # Read at most 1 byte ('0' or '1') + ) + + set(${check} ${key_value} PARENT_SCOPE) + return() + endif() + + # Flags that start with -Wno- can not be tested by + # check_compiler_flag, they will always pass, but -W can be + # tested, so to test -Wno- flags we test -W + # instead. + if("${option}" MATCHES "-Wno-(.*)") + string(REPLACE "-Wno-" "-W" possibly_translated_option "${option}") + else() + set(possibly_translated_option ${option}) + endif() + + check_compiler_flag(${lang} "${possibly_translated_option}" inner_check) + + set(${check} ${inner_check} PARENT_SCOPE) + + # Populate the cache + if(NOT (EXISTS ${key_path})) + + # This is racy. As often with race conditions, this one can easily be + # made worse and demonstrated with a simple delay: + # execute_process(COMMAND "sleep" "5") + # Delete the cache, add the sleep above and run twister with a + # large number of JOBS. Once it's done look at the log.txt file + # below and you will see that concurrent cmake processes created the + # same files multiple times. + + # While there are a number of reasons why this race seems both very + # unlikely and harmless, let's play it safe anyway and write to a + # private, temporary file first. All modern filesystems seem to + # support at least one atomic rename API and cmake's file(RENAME + # ...) officially leverages that. + string(RANDOM LENGTH 8 tempsuffix) + + file( + WRITE + "${key_path}_tmp_${tempsuffix}" + ${inner_check} + ) + file( + RENAME + "${key_path}_tmp_${tempsuffix}" "${key_path}" + ) + + # Populate a metadata file (only intended for trouble shooting) + # with information about the hash, the toolchain capability + # result, and the toolchain test. + file( + APPEND + ${ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR}/log.txt + "${inner_check} ${key} ${key_string}\n" + ) + endif() +endfunction() + +function(zephyr_check_compiler_flag_hardcoded lang option check exists) + # Various flags that are not supported for CXX may not be testable + # because they would produce a warning instead of an error during + # the test. Exclude them by toolchain-specific blocklist. + if((${lang} STREQUAL CXX) AND ("${option}" IN_LIST CXX_EXCLUDED_OPTIONS)) + set(${check} 0 PARENT_SCOPE) + set(${exists} 1 PARENT_SCOPE) + else() + # There does not exist a hardcoded check for this option. + set(${exists} 0 PARENT_SCOPE) + endif() +endfunction(zephyr_check_compiler_flag_hardcoded) + +# zephyr_linker_sources( [SORT_KEY ] ) +# +# is one or more .ld formatted files whose contents will be +# copied/included verbatim into the given in the global linker.ld. +# Preprocessor directives work inside . Relative paths are resolved +# relative to the calling file, like zephyr_sources(). +# is one of +# NOINIT Inside the noinit output section. +# RWDATA Inside the data output section. +# RODATA Inside the rodata output section. +# ROM_START Inside the first output section of the image. This option is +# currently only available on ARM Cortex-M, ARM Cortex-R, +# x86, ARC, openisa_rv32m1, and RISC-V. +# RAM_SECTIONS Inside the RAMABLE_REGION GROUP, not initialized. +# DATA_SECTIONS Inside the RAMABLE_REGION GROUP, initialized. +# RAMFUNC_SECTION Inside the RAMFUNC RAMABLE_REGION GROUP, not initialized. +# NOCACHE_SECTION Inside the NOCACHE section +# SECTIONS Near the end of the file. Don't use this when linking into +# RAMABLE_REGION, use RAM_SECTIONS instead. +# PINNED_RODATA Similar to RODATA but pinned in memory. +# PINNED_RAM_SECTIONS +# Similar to RAM_SECTIONS but pinned in memory. +# PINNED_DATA_SECTIONS +# Similar to DATA_SECTIONS but pinned in memory. +# is an optional key to sort by inside of each location. The key must +# be alphanumeric, and the keys are sorted alphabetically. If no key is +# given, the key 'default' is used. Keys are case-sensitive. +# +# Use NOINIT, RWDATA, and RODATA unless they don't work for your use case. +# +# When placing into NOINIT, RWDATA, RODATA, ROM_START, RAMFUNC_SECTION, +# NOCACHE_SECTION the contents of the files will be placed inside +# an output section, so assume the section definition is already present, e.g.: +# _mysection_start = .; +# KEEP(*(.mysection)); +# _mysection_end = .; +# _mysection_size = ABSOLUTE(_mysection_end - _mysection_start); +# +# When placing into SECTIONS, RAM_SECTIONS or DATA_SECTIONS, the files must +# instead define their own output sections to achieve the same thing: +# SECTION_PROLOGUE(.mysection,,) +# { +# _mysection_start = .; +# KEEP(*(.mysection)) +# _mysection_end = .; +# } GROUP_LINK_IN(ROMABLE_REGION) +# _mysection_size = _mysection_end - _mysection_start; +# +# Note about the above examples: If the first example was used with RODATA, and +# the second with SECTIONS, the two examples do the same thing from a user +# perspective. +# +# Friendly reminder: Beware of the different ways the location counter ('.') +# behaves inside vs. outside section definitions. +function(zephyr_linker_sources location) + # Set up the paths to the destination files. These files are #included inside + # the global linker.ld. + set(snippet_base "${__build_dir}/include/generated") + set(sections_path "${snippet_base}/snippets-sections.ld") + set(ram_sections_path "${snippet_base}/snippets-ram-sections.ld") + set(data_sections_path "${snippet_base}/snippets-data-sections.ld") + set(rom_start_path "${snippet_base}/snippets-rom-start.ld") + set(noinit_path "${snippet_base}/snippets-noinit.ld") + set(rwdata_path "${snippet_base}/snippets-rwdata.ld") + set(rodata_path "${snippet_base}/snippets-rodata.ld") + set(ramfunc_path "${snippet_base}/snippets-ramfunc-section.ld") + set(nocache_path "${snippet_base}/snippets-nocache-section.ld") + + set(pinned_ram_sections_path "${snippet_base}/snippets-pinned-ram-sections.ld") + set(pinned_data_sections_path "${snippet_base}/snippets-pinned-data-sections.ld") + set(pinned_rodata_path "${snippet_base}/snippets-pinned-rodata.ld") + + # Clear destination files if this is the first time the function is called. + get_property(cleared GLOBAL PROPERTY snippet_files_cleared) + if (NOT DEFINED cleared) + file(WRITE ${sections_path} "") + file(WRITE ${ram_sections_path} "") + file(WRITE ${data_sections_path} "") + file(WRITE ${rom_start_path} "") + file(WRITE ${noinit_path} "") + file(WRITE ${rwdata_path} "") + file(WRITE ${rodata_path} "") + file(WRITE ${ramfunc_path} "") + file(WRITE ${nocache_path} "") + file(WRITE ${pinned_ram_sections_path} "") + file(WRITE ${pinned_data_sections_path} "") + file(WRITE ${pinned_rodata_path} "") + set_property(GLOBAL PROPERTY snippet_files_cleared true) + endif() + + # Choose destination file, based on the argument. + if ("${location}" STREQUAL "SECTIONS") + set(snippet_path "${sections_path}") + elseif("${location}" STREQUAL "RAM_SECTIONS") + set(snippet_path "${ram_sections_path}") + elseif("${location}" STREQUAL "DATA_SECTIONS") + set(snippet_path "${data_sections_path}") + elseif("${location}" STREQUAL "ROM_START") + set(snippet_path "${rom_start_path}") + elseif("${location}" STREQUAL "NOINIT") + set(snippet_path "${noinit_path}") + elseif("${location}" STREQUAL "RWDATA") + set(snippet_path "${rwdata_path}") + elseif("${location}" STREQUAL "RODATA") + set(snippet_path "${rodata_path}") + elseif("${location}" STREQUAL "RAMFUNC_SECTION") + set(snippet_path "${ramfunc_path}") + elseif("${location}" STREQUAL "NOCACHE_SECTION") + set(snippet_path "${nocache_path}") + elseif("${location}" STREQUAL "PINNED_RAM_SECTIONS") + set(snippet_path "${pinned_ram_sections_path}") + elseif("${location}" STREQUAL "PINNED_DATA_SECTIONS") + set(snippet_path "${pinned_data_sections_path}") + elseif("${location}" STREQUAL "PINNED_RODATA") + set(snippet_path "${pinned_rodata_path}") + else() + message(fatal_error "Must choose valid location for linker snippet.") + endif() + + cmake_parse_arguments(L "" "SORT_KEY" "" ${ARGN}) + set(SORT_KEY default) + if(DEFINED L_SORT_KEY) + set(SORT_KEY ${L_SORT_KEY}) + endif() + + foreach(file IN ITEMS ${L_UNPARSED_ARGUMENTS}) + # Resolve path. + if(IS_ABSOLUTE ${file}) + set(path ${file}) + else() + set(path ${CMAKE_CURRENT_SOURCE_DIR}/${file}) + endif() + + if(IS_DIRECTORY ${path}) + message(FATAL_ERROR "zephyr_linker_sources() was called on a directory") + endif() + + # Find the relative path to the linker file from the include folder. + file(RELATIVE_PATH relpath ${ZEPHYR_BASE}/include ${path}) + + # Create strings to be written into the file + set (include_str "/* Sort key: \"${SORT_KEY}\" */#include \"${relpath}\"") + + # Add new line to existing lines, sort them, and write them back. + file(STRINGS ${snippet_path} lines) # Get current lines (without newlines). + list(APPEND lines ${include_str}) + list(SORT lines) + string(REPLACE ";" "\n;" lines "${lines}") # Add newline to each line. + file(WRITE ${snippet_path} ${lines} "\n") + endforeach() +endfunction(zephyr_linker_sources) + + +# Helper function for CONFIG_CODE_DATA_RELOCATION +# This function may either be invoked with a list of files, or a library +# name to relocate. +# +# The FILES directive will relocate a list of files (wildcards supported) +# This directive will relocate file1. and file2.c to SRAM: +# zephyr_code_relocate(FILES file1.c file2.c LOCATION SRAM) +# Note, files can also be passed as a comma separated list to support using +# cmake generator arguments +# +# The LIBRARY directive will relocate a library +# This directive will relocate the target my_lib to SRAM: +# zephyr_code_relocate(LIBRARY my_lib SRAM) +# +# The following optional arguments are supported: +# - NOCOPY: this flag indicates that the file data does not need to be copied +# at boot time (For example, for flash XIP). +# - PHDR [program_header]: add program header. Used on Xtensa platforms. +function(zephyr_code_relocate) + set(options NOCOPY) + set(single_args LIBRARY LOCATION PHDR) + set(multi_args FILES) + cmake_parse_arguments(CODE_REL "${options}" "${single_args}" + "${multi_args}" ${ARGN}) + # Argument validation + if(CODE_REL_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_code_relocate(${ARGV0} ...) " + "given unknown arguments: ${CODE_REL_UNPARSED_ARGUMENTS}") + endif() + if((NOT CODE_REL_FILES) AND (NOT CODE_REL_LIBRARY)) + message(FATAL_ERROR + "zephyr_code_relocate() requires either FILES or LIBRARY be provided") + endif() + if(CODE_REL_FILES AND CODE_REL_LIBRARY) + message(FATAL_ERROR "zephyr_code_relocate() only accepts " + "one argument between FILES and LIBRARY") + endif() + if(NOT CODE_REL_LOCATION) + message(FATAL_ERROR "zephyr_code_relocate() requires a LOCATION argument") + endif() + if(CODE_REL_LIBRARY) + # Use cmake generator expression to convert library to file list + set(genex_src_dir "$") + set(genex_src_list "$") + set(file_list + "${genex_src_dir}/$${genex_src_dir}/>") + else() + # Check if CODE_REL_FILES is a generator expression, if so leave it + # untouched. + string(GENEX_STRIP "${CODE_REL_FILES}" no_genex) + if(CODE_REL_FILES STREQUAL no_genex) + # no generator expression in CODE_REL_FILES, check if list of files + # is absolute + foreach(file ${CODE_REL_FILES}) + if(NOT IS_ABSOLUTE ${file}) + set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file}) + endif() + list(APPEND file_list ${file}) + endforeach() + else() + # Generator expression is present in file list. Leave the list untouched. + set(file_list ${CODE_REL_FILES}) + endif() + endif() + if(NOT CODE_REL_NOCOPY) + set(copy_flag COPY) + else() + set(copy_flag NOCOPY) + endif() + if(CODE_REL_PHDR) + set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}") + endif() + # We use the "|" character to separate code relocation directives instead + # of using CMake lists. This way, the ";" character can be reserved for + # generator expression file lists. + get_property(code_rel_str TARGET code_data_relocation_target + PROPERTY COMPILE_DEFINITIONS) + set_property(TARGET code_data_relocation_target + PROPERTY COMPILE_DEFINITIONS + "${code_rel_str}|${CODE_REL_LOCATION}:${copy_flag}:${file_list}") +endfunction() + +# Usage: +# check_dtc_flag("-Wtest" DTC_WARN_TEST) +# +# Writes 1 to the output variable 'ok' if +# the flag is supported, otherwise writes 0. +# +# using +function(check_dtc_flag flag ok) + execute_process( + COMMAND + ${DTC} ${flag} -v + ERROR_QUIET + OUTPUT_QUIET + RESULT_VARIABLE dtc_check_ret + ) + if (dtc_check_ret EQUAL 0) + set(${ok} 1 PARENT_SCOPE) + else() + set(${ok} 0 PARENT_SCOPE) + endif() +endfunction() + +# Function to round number to next power of two. +# +# Usage: +# pow2round() +# +# Example: +# set(test 2) +# pow2round(test) +# # test is still 2 +# +# set(test 5) +# pow2round(test) +# # test is now 8 +# +# Arguments: +# n = Variable containing the number to round +function(pow2round n) + math(EXPR x "${${n}} & (${${n}} - 1)") + if(${x} EQUAL 0) + return() + endif() + + math(EXPR ${n} "${${n}} | (${${n}} >> 1)") + math(EXPR ${n} "${${n}} | (${${n}} >> 2)") + math(EXPR ${n} "${${n}} | (${${n}} >> 4)") + math(EXPR ${n} "${${n}} | (${${n}} >> 8)") + math(EXPR ${n} "${${n}} | (${${n}} >> 16)") + math(EXPR ${n} "${${n}} | (${${n}} >> 32)") + math(EXPR ${n} "${${n}} + 1") + set(${n} ${${n}} PARENT_SCOPE) +endfunction() + +# Function to create a build string based on BOARD, BOARD_REVISION, and BUILD +# type. +# +# This is a common function to ensure that build strings are always created +# in a uniform way. +# +# Usage: +# zephyr_build_string( +# BOARD +# [BOARD_REVISION ] +# [BUILD ] +# ) +# +# : Output variable where the build string will be returned. +# BOARD : Board name to use when creating the build string. +# BOARD_REVISION : Board revision to use when creating the build string. +# BUILD : Build type to use when creating the build string. +# +# Examples +# calling +# zephyr_build_string(build_string BOARD alpha BUILD debug) +# will return the string `alpha_debug` in `build_string` parameter. +# +# calling +# zephyr_build_string(build_string BOARD alpha BOARD_REVISION 1.0.0 BUILD debug) +# will return the string `alpha_1_0_0_debug` in `build_string` parameter. +# +function(zephyr_build_string outvar) + set(single_args BOARD BOARD_REVISION BUILD) + + cmake_parse_arguments(BUILD_STR "" "${single_args}" "" ${ARGN}) + if(BUILD_STR_UNPARSED_ARGUMENTS) + message(FATAL_ERROR + "zephyr_build_string(${ARGV0} ...) given unknown arguments:" + " ${BUILD_STR_UNPARSED_ARGUMENTS}" + ) + endif() + + if(DEFINED BUILD_STR_BOARD_REVISION AND NOT BUILD_STR_BOARD) + message(FATAL_ERROR + "zephyr_build_string(${ARGV0} BOARD_REVISION ${BUILD_STR_BOARD_REVISION} ...)" + " given without BOARD argument, please specify BOARD" + ) + endif() + + set(${outvar} ${BUILD_STR_BOARD}) + + if(DEFINED BUILD_STR_BOARD_REVISION) + string(REPLACE "." "_" revision_string ${BUILD_STR_BOARD_REVISION}) + set(${outvar} "${${outvar}}_${revision_string}") + endif() + + if(BUILD_STR_BUILD) + set(${outvar} "${${outvar}}_${BUILD_STR_BUILD}") + endif() + + # This updates the provided outvar in parent scope (callers scope) + set(${outvar} ${${outvar}} PARENT_SCOPE) +endfunction() + +######################################################## +# 2. Kconfig-aware extensions +######################################################## +# +# Kconfig is a configuration language developed for the Linux +# kernel. The below functions integrate CMake with Kconfig. +# + +# 2.1 Misc +# +# import_kconfig( [] [TARGET ]) +# +# Parse a KConfig fragment (typically with extension .config) and +# introduce all the symbols that are prefixed with 'prefix' into the +# CMake namespace. List all created variable names in the 'keys' +# output variable if present. +# +# : symbol prefix of settings in the Kconfig fragment. +# : absolute path to the config fragment file. +# : output variable which will be populated with variable +# names loaded from the kconfig fragment. +# TARGET : set all symbols on instead of adding them to the +# CMake namespace. +function(import_kconfig prefix kconfig_fragment) + cmake_parse_arguments(IMPORT_KCONFIG "" "TARGET" "" ${ARGN}) + # Parse the lines prefixed with 'prefix' in ${kconfig_fragment} + file( + STRINGS + ${kconfig_fragment} + DOT_CONFIG_LIST + REGEX "^${prefix}" + ENCODING "UTF-8" + ) + + foreach (CONFIG ${DOT_CONFIG_LIST}) + # CONFIG could look like: CONFIG_NET_BUF=y + + # Match the first part, the variable name + string(REGEX MATCH "[^=]+" CONF_VARIABLE_NAME ${CONFIG}) + + # Match the second part, variable value + string(REGEX MATCH "=(.+$)" CONF_VARIABLE_VALUE ${CONFIG}) + # The variable name match we just did included the '=' symbol. To just get the + # part on the RHS we use match group 1 + set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1}) + + if("${CONF_VARIABLE_VALUE}" MATCHES "^\"(.*)\"$") # Is surrounded by quotes + set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1}) + endif() + + if(DEFINED IMPORT_KCONFIG_TARGET) + set_property(TARGET ${IMPORT_KCONFIG_TARGET} APPEND PROPERTY "kconfigs" "${CONF_VARIABLE_NAME}") + set_property(TARGET ${IMPORT_KCONFIG_TARGET} PROPERTY "${CONF_VARIABLE_NAME}" "${CONF_VARIABLE_VALUE}") + else() + set("${CONF_VARIABLE_NAME}" "${CONF_VARIABLE_VALUE}" PARENT_SCOPE) + endif() + list(APPEND keys "${CONF_VARIABLE_NAME}") + endforeach() + + list(LENGTH IMPORT_KCONFIG_UNPARSED_ARGUMENTS unparsed_length) + if(unparsed_length GREATER 0) + if(unparsed_length GREATER 1) + # Two mandatory arguments and one optional, anything after that is an error. + list(GET IMPORT_KCONFIG_UNPARSED_ARGUMENTS 1 first_invalid) + message(FATAL_ERROR "Unexpected argument after '': import_kconfig(... ${first_invalid})") + endif() + set(${IMPORT_KCONFIG_UNPARSED_ARGUMENTS} "${keys}" PARENT_SCOPE) + endif() +endfunction() + +######################################################## +# 3. CMake-generic extensions +######################################################## +# +# These functions extend the CMake API in a way that is not particular +# to Zephyr. Primarily they work around limitations in the CMake +# language to allow cleaner build scripts. + +# 3.1. *_ifdef +# +# Functions for conditionally executing CMake functions with oneliners +# e.g. +# +# if(CONFIG_FFT) +# zephyr_library_source( +# fft_32.c +# fft_utils.c +# ) +# endif() +# +# Becomes +# +# zephyr_source_ifdef( +# CONFIG_FFT +# fft_32.c +# fft_utils.c +# ) +# +# More Generally +# "_ifdef(CONDITION args)" +# Becomes +# """ +# if(CONDITION) +# (args) +# endif() +# """ +# +# ifdef functions are added on an as-need basis. See +# https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for +# a list of available functions. +function(add_subdirectory_ifdef feature_toggle source_dir) + if(${${feature_toggle}}) + add_subdirectory(${source_dir} ${ARGN}) + endif() +endfunction() + +function(target_sources_ifdef feature_toggle target scope item) + if(${${feature_toggle}}) + target_sources(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_compile_definitions_ifdef feature_toggle target scope item) + if(${${feature_toggle}}) + target_compile_definitions(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_include_directories_ifdef feature_toggle target scope item) + if(${${feature_toggle}}) + target_include_directories(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_link_libraries_ifdef feature_toggle target item) + if(${${feature_toggle}}) + target_link_libraries(${target} ${item} ${ARGN}) + endif() +endfunction() + +function(add_compile_option_ifdef feature_toggle option) + if(${${feature_toggle}}) + add_compile_options(${option}) + endif() +endfunction() + +function(target_compile_option_ifdef feature_toggle target scope option) + if(${feature_toggle}) + target_compile_options(${target} ${scope} ${option}) + endif() +endfunction() + +function(target_cc_option_ifdef feature_toggle target scope option) + if(${feature_toggle}) + target_cc_option(${target} ${scope} ${option}) + endif() +endfunction() + +function(zephyr_library_sources_ifdef feature_toggle source) + if(${${feature_toggle}}) + zephyr_library_sources(${source} ${ARGN}) + endif() +endfunction() + +function(zephyr_sources_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_sources(${ARGN}) + endif() +endfunction() + +function(zephyr_cc_option_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_cc_option(${ARGN}) + endif() +endfunction() + +function(zephyr_ld_option_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_ld_options(${ARGN}) + endif() +endfunction() + +function(zephyr_link_libraries_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_link_libraries(${ARGN}) + endif() +endfunction() + +function(zephyr_compile_options_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_compile_options(${ARGN}) + endif() +endfunction() + +function(zephyr_compile_definitions_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_compile_definitions(${ARGN}) + endif() +endfunction() + +function(zephyr_include_directories_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_include_directories(${ARGN}) + endif() +endfunction() + +function(zephyr_library_compile_definitions_ifdef feature_toggle item) + if(${${feature_toggle}}) + zephyr_library_compile_definitions(${item} ${ARGN}) + endif() +endfunction() + +function(zephyr_library_include_directories_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_library_include_directories(${ARGN}) + endif() +endfunction() + +function(zephyr_library_compile_options_ifdef feature_toggle item) + if(${${feature_toggle}}) + zephyr_library_compile_options(${item} ${ARGN}) + endif() +endfunction() + +function(zephyr_link_interface_ifdef feature_toggle interface) + if(${${feature_toggle}}) + target_link_libraries(${interface} INTERFACE zephyr_interface) + endif() +endfunction() + +function(zephyr_library_link_libraries_ifdef feature_toggle item) + if(${${feature_toggle}}) + zephyr_library_link_libraries(${item}) + endif() +endfunction() + +function(zephyr_linker_sources_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_linker_sources(${ARGN}) + endif() +endfunction() + +macro(list_append_ifdef feature_toggle list) + if(${${feature_toggle}}) + list(APPEND ${list} ${ARGN}) + endif() +endmacro() + +# 3.2. *_ifndef +# See 3.1 *_ifdef +function(set_ifndef variable value) + if(NOT ${variable}) + set(${variable} ${value} ${ARGN} PARENT_SCOPE) + endif() +endfunction() + +function(add_subdirectory_ifndef feature_toggle source_dir) + if(NOT ${feature_toggle}) + add_subdirectory(${source_dir} ${ARGN}) + endif() +endfunction() + +function(target_sources_ifndef feature_toggle target scope item) + if(NOT ${feature_toggle}) + target_sources(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_compile_definitions_ifndef feature_toggle target scope item) + if(NOT ${feature_toggle}) + target_compile_definitions(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_include_directories_ifndef feature_toggle target scope item) + if(NOT ${feature_toggle}) + target_include_directories(${target} ${scope} ${item} ${ARGN}) + endif() +endfunction() + +function(target_link_libraries_ifndef feature_toggle target item) + if(NOT ${feature_toggle}) + target_link_libraries(${target} ${item} ${ARGN}) + endif() +endfunction() + +function(add_compile_option_ifndef feature_toggle option) + if(NOT ${feature_toggle}) + add_compile_options(${option}) + endif() +endfunction() + +function(target_compile_option_ifndef feature_toggle target scope option) + if(NOT ${feature_toggle}) + target_compile_options(${target} ${scope} ${option}) + endif() +endfunction() + +function(target_cc_option_ifndef feature_toggle target scope option) + if(NOT ${feature_toggle}) + target_cc_option(${target} ${scope} ${option}) + endif() +endfunction() + +function(zephyr_library_sources_ifndef feature_toggle source) + if(NOT ${feature_toggle}) + zephyr_library_sources(${source} ${ARGN}) + endif() +endfunction() + +function(zephyr_sources_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_sources(${ARGN}) + endif() +endfunction() + +function(zephyr_cc_option_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_cc_option(${ARGN}) + endif() +endfunction() + +function(zephyr_ld_option_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_ld_options(${ARGN}) + endif() +endfunction() + +function(zephyr_link_libraries_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_link_libraries(${ARGN}) + endif() +endfunction() + +function(zephyr_compile_options_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_compile_options(${ARGN}) + endif() +endfunction() + +function(zephyr_compile_definitions_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_compile_definitions(${ARGN}) + endif() +endfunction() + +function(zephyr_include_directories_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_include_directories(${ARGN}) + endif() +endfunction() + +function(zephyr_library_compile_definitions_ifndef feature_toggle item) + if(NOT ${feature_toggle}) + zephyr_library_compile_definitions(${item} ${ARGN}) + endif() +endfunction() + +function(zephyr_library_include_directories_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_library_include_directories(${ARGN}) + endif() +endfunction() + +function(zephyr_library_compile_options_ifndef feature_toggle item) + if(NOT ${feature_toggle}) + zephyr_library_compile_options(${item} ${ARGN}) + endif() +endfunction() + +function(zephyr_link_interface_ifndef feature_toggle interface) + if(NOT ${feature_toggle}) + target_link_libraries(${interface} INTERFACE zephyr_interface) + endif() +endfunction() + +function(zephyr_library_link_libraries_ifndef feature_toggle item) + if(NOT ${feature_toggle}) + zephyr_library_link_libraries(${item}) + endif() +endfunction() + +function(zephyr_linker_sources_ifndef feature_toggle) + if(NOT ${feature_toggle}) + zephyr_linker_sources(${ARGN}) + endif() +endfunction() + +macro(list_append_ifndef feature_toggle list) + if(NOT ${feature_toggle}) + list(APPEND ${list} ${ARGN}) + endif() +endmacro() + +# 3.3. *_option Compiler-compatibility checks +# +# Utility functions for silently omitting compiler flags when the +# compiler lacks support. *_cc_option was ported from KBuild, see +# cc-option in +# https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt + +# Writes 1 to the output variable 'ok' for the language 'lang' if +# the flag is supported, otherwise writes 0. +# +# lang must be C or CXX +# +# TODO: Support ASM +# +# Usage: +# +# check_compiler_flag(C "-Wall" my_check) +# print(my_check) # my_check is now 1 +function(check_compiler_flag lang option ok) + if(NOT DEFINED CMAKE_REQUIRED_QUIET) + set(CMAKE_REQUIRED_QUIET 1) + endif() + + string(MAKE_C_IDENTIFIER + "check${option}_${lang}_${CMAKE_REQUIRED_FLAGS}" + ${ok} + ) + + if(${lang} STREQUAL C) + check_c_compiler_flag("${option}" ${${ok}}) + else() + check_cxx_compiler_flag("${option}" ${${ok}}) + endif() + + if(${${${ok}}}) + set(ret 1) + else() + set(ret 0) + endif() + + set(${ok} ${ret} PARENT_SCOPE) +endfunction() + +function(target_cc_option target scope option) + target_cc_option_fallback(${target} ${scope} ${option} "") +endfunction() + +# Support an optional second option for when the first option is not +# supported. +function(target_cc_option_fallback target scope option1 option2) + if(CONFIG_CPP) + foreach(lang C CXX) + # For now, we assume that all flags that apply to C/CXX also + # apply to ASM. + zephyr_check_compiler_flag(${lang} ${option1} check) + if(${check}) + target_compile_options(${target} ${scope} + $<$:${option1}> + $<$:${option1}> + ) + elseif(option2) + target_compile_options(${target} ${scope} + $<$:${option2}> + $<$:${option2}> + ) + endif() + endforeach() + else() + zephyr_check_compiler_flag(C ${option1} check) + if(${check}) + target_compile_options(${target} ${scope} ${option1}) + elseif(option2) + target_compile_options(${target} ${scope} ${option2}) + endif() + endif() +endfunction() + +function(target_ld_options target scope) + zephyr_get_parse_args(args ${ARGN}) + list(REMOVE_ITEM ARGN NO_SPLIT) + + foreach(option ${ARGN}) + if(args_NO_SPLIT) + set(option ${ARGN}) + endif() + string(JOIN "" check_identifier "check" ${option}) + string(MAKE_C_IDENTIFIER ${check_identifier} check) + + set(SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + string(JOIN " " CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ${option}) + zephyr_check_compiler_flag(C "" ${check}) + set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS}) + + target_link_libraries_ifdef(${check} ${target} ${scope} ${option}) + + if(args_NO_SPLIT) + break() + endif() + endforeach() +endfunction() + +# 3.3.1 Toolchain integration +# +# 'toolchain_parse_make_rule' is a function that parses the output of +# 'gcc -M'. +# +# The argument 'input_file' is in input parameter with the path to the +# file with the dependency information. +# +# The argument 'include_files' is an output parameter with the result +# of parsing the include files. +function(toolchain_parse_make_rule input_file include_files) + file(STRINGS ${input_file} input) + + # The file is formatted like this: + # empty_file.o: misc/empty_file.c \ + # nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts \ + # nrf52840_qiaa.dtsi + + # The dep file will contain `\` for line continuation. + # This results in `\;` which is then treated a the char `;` instead of + # the element separator, so let's get the pure `;` back. + string(REPLACE "\;" ";" input_as_list ${input}) + + # Pop the first line and treat it specially + list(POP_FRONT input_as_list first_input_line) + string(FIND ${first_input_line} ": " index) + math(EXPR j "${index} + 2") + string(SUBSTRING ${first_input_line} ${j} -1 first_include_file) + + # Remove whitespace before and after filename and convert to CMake path. + string(STRIP "${first_include_file}" first_include_file) + file(TO_CMAKE_PATH "${first_include_file}" first_include_file) + set(result "${first_include_file}") + + # Remove whitespace before and after filename and convert to CMake path. + foreach(file ${input_as_list}) + string(STRIP "${file}" file) + file(TO_CMAKE_PATH "${file}" file) + list(APPEND result "${file}") + endforeach() + + set(${include_files} ${result} PARENT_SCOPE) +endfunction() + +# 'check_set_linker_property' is a function that check the provided linker +# flag and only set the linker property if the check succeeds +# +# This function is similar in nature to the CMake set_property function, but +# with the extension that it will check that the linker supports the flag before +# setting the property. +# +# APPEND: Flag indicated that the property should be appended to the existing +# value list for the property. +# TARGET: Name of target on which to add the property (commonly: linker) +# PROPERTY: Name of property with the value(s) following immediately after +# property name +function(check_set_linker_property) + set(options APPEND) + set(single_args TARGET) + set(multi_args PROPERTY) + cmake_parse_arguments(LINKER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN}) + + if(LINKER_PROPERTY_APPEND) + set(APPEND "APPEND") + endif() + + list(GET LINKER_PROPERTY_PROPERTY 0 property) + list(REMOVE_AT LINKER_PROPERTY_PROPERTY 0) + set(option ${LINKER_PROPERTY_PROPERTY}) + + string(MAKE_C_IDENTIFIER check${option} check) + + set(SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${option}") + zephyr_check_compiler_flag(C "" ${check}) + set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS}) + + if(${${check}}) + set_property(TARGET ${LINKER_PROPERTY_TARGET} ${APPEND} PROPERTY ${property} ${option}) + endif() +endfunction() + +# 'set_compiler_property' is a function that sets the property for the C and +# C++ property targets used for toolchain abstraction. +# +# This function is similar in nature to the CMake set_property function, but +# with the extension that it will set the property on both the compile and +# compiler-cpp targets. +# +# APPEND: Flag indicated that the property should be appended to the existing +# value list for the property. +# PROPERTY: Name of property with the value(s) following immediately after +# property name +function(set_compiler_property) + set(options APPEND) + set(multi_args PROPERTY) + cmake_parse_arguments(COMPILER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN}) + if(COMPILER_PROPERTY_APPEND) + set(APPEND "APPEND") + set(APPEND-CPP "APPEND") + endif() + + set_property(TARGET compiler ${APPEND} PROPERTY ${COMPILER_PROPERTY_PROPERTY}) + set_property(TARGET compiler-cpp ${APPEND} PROPERTY ${COMPILER_PROPERTY_PROPERTY}) +endfunction() + +# 'check_set_compiler_property' is a function that check the provided compiler +# flag and only set the compiler or compiler-cpp property if the check succeeds +# +# This function is similar in nature to the CMake set_property function, but +# with the extension that it will check that the compiler supports the flag +# before setting the property on compiler or compiler-cpp targets. +# +# To test flags together, such as '-Wformat -Wformat-security', an option group +# can be specified by using shell-like quoting along with a 'SHELL:' prefix. +# The 'SHELL:' prefix will be dropped before testing, so that +# '"SHELL:-Wformat -Wformat-security"' becomes '-Wformat -Wformat-security' for +# testing. +# +# APPEND: Flag indicated that the property should be appended to the existing +# value list for the property. +# PROPERTY: Name of property with the value(s) following immediately after +# property name +function(check_set_compiler_property) + set(options APPEND) + set(multi_args PROPERTY) + cmake_parse_arguments(COMPILER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN}) + if(COMPILER_PROPERTY_APPEND) + set(APPEND "APPEND") + set(APPEND-CPP "APPEND") + endif() + + list(GET COMPILER_PROPERTY_PROPERTY 0 property) + list(REMOVE_AT COMPILER_PROPERTY_PROPERTY 0) + + foreach(option ${COMPILER_PROPERTY_PROPERTY}) + if(${option} MATCHES "^SHELL:") + string(REGEX REPLACE "^SHELL:" "" option ${option}) + separate_arguments(option UNIX_COMMAND ${option}) + endif() + + if(CONFIG_CPP) + zephyr_check_compiler_flag(CXX "${option}" check) + + if(${check}) + set_property(TARGET compiler-cpp ${APPEND-CPP} PROPERTY ${property} ${option}) + set(APPEND-CPP "APPEND") + endif() + endif() + + zephyr_check_compiler_flag(C "${option}" check) + + if(${check}) + set_property(TARGET compiler ${APPEND} PROPERTY ${property} ${option}) + set(APPEND "APPEND") + endif() + endforeach() +endfunction() + + +# 3.4. Debugging CMake + +# Usage: +# print(BOARD) +# +# will print: "BOARD: nrf52dk_nrf52832" +function(print arg) + message(STATUS "${arg}: ${${arg}}") +endfunction() + +# Usage: +# assert(ZEPHYR_TOOLCHAIN_VARIANT "ZEPHYR_TOOLCHAIN_VARIANT not set.") +# +# will cause a FATAL_ERROR and print an error message if the first +# expression is false +macro(assert test comment) + if(NOT ${test}) + message(FATAL_ERROR "Assertion failed: ${comment}") + endif() +endmacro() + +# Usage: +# assert_not(OBSOLETE_VAR "OBSOLETE_VAR has been removed; use NEW_VAR instead") +# +# will cause a FATAL_ERROR and print an error message if the first +# expression is true +macro(assert_not test comment) + if(${test}) + message(FATAL_ERROR "Assertion failed: ${comment}") + endif() +endmacro() + +# Usage: +# assert_exists(CMAKE_READELF) +# +# will cause a FATAL_ERROR if there is no file or directory behind the +# variable +macro(assert_exists var) + if(NOT EXISTS ${${var}}) + message(FATAL_ERROR "No such file or directory: ${var}: '${${var}}'") + endif() +endmacro() + +# 3.5. File system management +function(generate_unique_target_name_from_filename filename target_name) + get_filename_component(basename ${filename} NAME) + string(REPLACE "." "_" x ${basename}) + string(REPLACE "@" "_" x ${x}) + + string(MD5 unique_chars ${filename}) + + set(${target_name} gen_${x}_${unique_chars} PARENT_SCOPE) +endfunction() + +# Usage: +# zephyr_file( ...) +# +# Zephyr file function extension. +# This function currently supports the following +# +# APPLICATION_ROOT : Check all paths in provided variable, and convert +# those paths that are defined with `-D=` +# to absolute path, relative from `APPLICATION_SOURCE_DIR` +# Issue an error for any relative path not specified +# by user with `-D` +# +# returns an updated list of absolute paths +# +# CONF_FILES : Find all configuration files in path and return them in a +# list. Configuration files will be: +# - DTS: Overlay files (.overlay) +# - Kconfig: Config fragments (.conf) +# The conf file search will return existing configuration +# files for the current board. +# CONF_FILES takes the following additional arguments: +# BOARD : Find configuration files for specified board. +# BOARD_REVISION : Find configuration files for specified board +# revision. Requires BOARD to be specified. +# +# If no board is given the current BOARD and +# BOARD_REVISION will be used. +# +# DTS : List to append DTS overlay files in to +# KCONF : List to append Kconfig fragment files in to +# BUILD : Build type to include for search. +# For example: +# BUILD debug, will look for _debug.conf +# and _debug.overlay, instead of .conf +# +function(zephyr_file) + set(file_options APPLICATION_ROOT CONF_FILES) + if((ARGC EQUAL 0) OR (NOT (ARGV0 IN_LIST file_options))) + message(FATAL_ERROR "No given to `zephyr_file( ...)` function,\n \ +Please provide one of following: APPLICATION_ROOT, CONF_FILES") + endif() + + if(${ARGV0} STREQUAL APPLICATION_ROOT) + set(single_args APPLICATION_ROOT) + elseif(${ARGV0} STREQUAL CONF_FILES) + set(single_args CONF_FILES BOARD BOARD_REVISION DTS KCONF BUILD) + endif() + + cmake_parse_arguments(FILE "" "${single_args}" "" ${ARGN}) + if(FILE_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_file(${ARGV0} ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}") + endif() + + + if(FILE_APPLICATION_ROOT) + # Note: user can do: `-D=` and app can at same + # time specify `list(APPEND )` + # Thus need to check and update only CACHED variables (-D). + set(CACHED_PATH $CACHE{${FILE_APPLICATION_ROOT}}) + foreach(path ${CACHED_PATH}) + # The cached variable is relative path, i.e. provided by `-D` or + # `set( CACHE)`, so let's update current scope variable to absolute + # path from `APPLICATION_SOURCE_DIR`. + if(NOT IS_ABSOLUTE ${path}) + set(abs_path ${APPLICATION_SOURCE_DIR}/${path}) + list(FIND ${FILE_APPLICATION_ROOT} ${path} index) + if(NOT ${index} LESS 0) + list(REMOVE_AT ${FILE_APPLICATION_ROOT} ${index}) + list(INSERT ${FILE_APPLICATION_ROOT} ${index} ${abs_path}) + endif() + endif() + endforeach() + + # Now all cached relative paths has been updated. + # Let's check if anyone uses relative path as scoped variable, and fail + foreach(path ${${FILE_APPLICATION_ROOT}}) + if(NOT IS_ABSOLUTE ${path}) + message(FATAL_ERROR +"Relative path encountered in scoped variable: ${FILE_APPLICATION_ROOT}, value=${path}\n \ +Please adjust any `set(${FILE_APPLICATION_ROOT} ${path})` or `list(APPEND ${FILE_APPLICATION_ROOT} ${path})`\n \ +to absolute path using `\${CMAKE_CURRENT_SOURCE_DIR}/${path}` or similar. \n \ +Relative paths are only allowed with `-D${ARGV1}=`") + endif() + endforeach() + + # This updates the provided argument in parent scope (callers scope) + set(${FILE_APPLICATION_ROOT} ${${FILE_APPLICATION_ROOT}} PARENT_SCOPE) + endif() + + if(FILE_CONF_FILES) + if(DEFINED FILE_BOARD_REVISION AND NOT FILE_BOARD) + message(FATAL_ERROR + "zephyr_file(${ARGV0} BOARD_REVISION ${FILE_BOARD_REVISION} ...)" + " given without BOARD argument, please specify BOARD" + ) + endif() + + if(NOT DEFINED FILE_BOARD) + # Defaulting to system wide settings when BOARD is not given as argument + set(FILE_BOARD ${BOARD}) + if(DEFINED BOARD_REVISION) + set(FILE_BOARD_REVISION ${BOARD_REVISION}) + endif() + endif() + + zephyr_build_string(filename + BOARD ${FILE_BOARD} + BUILD ${FILE_BUILD} + ) + set(filename_list ${filename}) + + zephyr_build_string(filename + BOARD ${FILE_BOARD} + BOARD_REVISION ${FILE_BOARD_REVISION} + BUILD ${FILE_BUILD} + ) + list(APPEND filename_list ${filename}) + list(REMOVE_DUPLICATES filename_list) + + if(FILE_DTS) + foreach(filename ${filename_list}) + if(EXISTS ${FILE_CONF_FILES}/${filename}.overlay) + list(APPEND ${FILE_DTS} ${FILE_CONF_FILES}/${filename}.overlay) + endif() + endforeach() + + # This updates the provided list in parent scope (callers scope) + set(${FILE_DTS} ${${FILE_DTS}} PARENT_SCOPE) + endif() + + if(FILE_KCONF) + foreach(filename ${filename_list}) + if(EXISTS ${FILE_CONF_FILES}/${filename}.conf) + list(APPEND ${FILE_KCONF} ${FILE_CONF_FILES}/${filename}.conf) + endif() + endforeach() + + # This updates the provided list in parent scope (callers scope) + set(${FILE_KCONF} ${${FILE_KCONF}} PARENT_SCOPE) + endif() + endif() +endfunction() + +# Usage: +# zephyr_file_copy( [ONLY_IF_DIFFERENT]) +# +# Zephyr file copy extension. +# This function is similar to CMake function +# 'file(COPY_FILE [ONLY_IF_DIFFERENT])' +# introduced with CMake 3.21. +# +# Because the minimal required CMake version with Zephyr is 3.20, this function +# is not guaranteed to be available. +# +# When using CMake version 3.21 or newer 'zephyr_file_copy()' simply calls +# 'file(COPY_FILE...)' directly. +# When using CMake version 3.20, the implementation will execute using CMake +# for running command line tool in a subprocess for identical functionality. +function(zephyr_file_copy oldname newname) + set(options ONLY_IF_DIFFERENT) + cmake_parse_arguments(ZEPHYR_FILE_COPY "${options}" "" "" ${ARGN}) + + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21.0) + if(ZEPHYR_FILE_COPY_ONLY_IF_DIFFERENT) + set(copy_file_options ONLY_IF_DIFFERENT) + endif() + file(COPY_FILE ${oldname} ${newname} ${copy_file_options}) + else() + if(ZEPHYR_FILE_COPY_ONLY_IF_DIFFERENT) + set(copy_file_command copy_if_different) + else() + set(copy_file_command copy) + endif() + execute_process( + COMMAND ${CMAKE_COMMAND} -E ${copy_file_command} ${oldname} ${newname} + ) + endif() +endfunction() + +# Usage: +# zephyr_string( ...) +# +# Zephyr string function extension. +# This function extends the CMake string function by providing additional +# manipulation arguments to CMake string. +# +# SANITIZE: Ensure that the output string does not contain any special +# characters. Special characters, such as -, +, =, $, etc. are +# converted to underscores '_'. +# +# SANITIZE TOUPPER: Ensure that the output string does not contain any special +# characters. Special characters, such as -, +, =, $, etc. are +# converted to underscores '_'. +# The sanitized string will be returned in UPPER case. +# +# returns the updated string +function(zephyr_string) + set(options SANITIZE TOUPPER) + cmake_parse_arguments(ZEPHYR_STRING "${options}" "" "" ${ARGN}) + + if (NOT ZEPHYR_STRING_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Function zephyr_string() called without a return variable") + endif() + + list(GET ZEPHYR_STRING_UNPARSED_ARGUMENTS 0 return_arg) + list(REMOVE_AT ZEPHYR_STRING_UNPARSED_ARGUMENTS 0) + + list(JOIN ZEPHYR_STRING_UNPARSED_ARGUMENTS "" work_string) + + if(ZEPHYR_STRING_SANITIZE) + string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" work_string ${work_string}) + endif() + + if(ZEPHYR_STRING_TOUPPER) + string(TOUPPER ${work_string} work_string) + endif() + + set(${return_arg} ${work_string} PARENT_SCOPE) +endfunction() + +# Usage: +# zephyr_list(TRANSFORM +# [OUTPUT_VARIABLE : This currently must be NORMALIZE_PATHS. This action +# converts the argument list to a ;-list with +# CMake path names, after passing its contents through +# a configure_file() transformation. The input list +# may be whitespace- or semicolon-separated. +# +# OUTPUT_VARIABLE: the result is normally stored in place, but +# an alternative variable to store the result +# can be provided with this. +function(zephyr_list transform list_var action) + # Parse arguments. + if(NOT "${transform}" STREQUAL "TRANSFORM") + message(FATAL_ERROR "the first argument must be TRANSFORM") + endif() + if(NOT "${action}" STREQUAL "NORMALIZE_PATHS") + message(FATAL_ERROR "the third argument must be NORMALIZE_PATHS") + endif() + set(single_args OUTPUT_VARIABLE) + cmake_parse_arguments(ZEPHYR_LIST "" "${single_args}" "" ${ARGN}) + if(DEFINED ZEPHYR_LIST_OUTPUT_VARIABLE) + set(out_var ${ZEPHYR_LIST_OUTPUT_VARIABLE}) + else() + set(out_var ${list_var}) + endif() + set(input ${${list_var}}) + + # Perform the transformation. + set(ret) + string(CONFIGURE "${input}" input_expanded) + string(REPLACE " " ";" input_raw_list "${input_expanded}") + foreach(file ${input_raw_list}) + file(TO_CMAKE_PATH "${file}" cmake_path_file) + list(APPEND ret ${cmake_path_file}) + endforeach() + + set(${out_var} ${ret} PARENT_SCOPE) +endfunction() + +# Usage: +# zephyr_var_name( ) +# +# Internal function for construction of scoped variable name expansion string. +# Examples: +# reading a current scope FOO variable is identical to expand ${FOO}. +# reading a cache scope FOO variable is identical to expand $CACHE{FOO}. +# +# this functions will return the var name in out var for the scope if it is +# defined, else it will set the outvar to undefined. +function(zephyr_var_name variable scope out) + if(scope STREQUAL "ENV" OR scope STREQUAL "CACHE") + if(DEFINED ${scope}{${variable}}) + set(${out} "$${scope}{${variable}}" PARENT_SCOPE) + else() + set(${out} PARENT_SCOPE) + endif() + else() + if(DEFINED ${scope}_${variable}) + set(${out} "${${scope}_${variable}}" PARENT_SCOPE) + else() + set(${out} PARENT_SCOPE) + endif() + endif() +endfunction() + +# Usage: +# zephyr_get( [MERGE [REVERSE]] [SYSBUILD [LOCAL|GLOBAL]] [VAR ...]) +# +# Return the value of as local scoped variable of same name. If MERGE +# is supplied, will return a list of found items. If REVERSE is supplied +# together with MERGE, the order of the list will be reversed before being +# returned. Reverse will happen before the list is returned and hence it will +# not change the order of precedence in which the list itself is constructed. +# +# VAR can be used either to store the result in a variable with a different +# name, or to look for values from multiple variables. +# zephyr_get(FOO VAR FOO_A FOO_B) +# zephyr_get(FOO MERGE VAR FOO_A FOO_B) +# +# zephyr_get() is a common function to provide a uniform way of supporting +# build settings that can be set from sysbuild, CMakeLists.txt, CMake cache, or +# in environment. +# +# The order of precedence for variables defined in multiple scopes: +# - Sysbuild defined when sysbuild is used. +# Sysbuild variables can be defined as global or local to specific image. +# Examples: +# - BOARD is considered a global sysbuild cache variable +# - blinky_BOARD is considered a local sysbuild cache variable only for the +# blinky image. +# If no sysbuild scope is specified, GLOBAL is assumed. +# If using MERGE then SYSBUILD GLOBAL will get both the local and global +# sysbuild scope variables (in that order, if both exist). +# - CMake cache, set by `-D=` or `set( CACHE ...) +# - Environment +# - Locally in CMakeLists.txt before 'find_package(Zephyr)' +# +# For example, if ZEPHYR_TOOLCHAIN_VARIANT is set in environment but locally +# overridden by setting ZEPHYR_TOOLCHAIN_VARIANT directly in the CMake cache +# using `-DZEPHYR_TOOLCHAIN_VARIANT=`, then the value from the cache is +# returned. +function(zephyr_get variable) + cmake_parse_arguments(GET_VAR "MERGE;REVERSE" "SYSBUILD" "VAR" ${ARGN}) + + if(DEFINED GET_VAR_SYSBUILD) + if(NOT ("${GET_VAR_SYSBUILD}" STREQUAL "GLOBAL" OR + "${GET_VAR_SYSBUILD}" STREQUAL "LOCAL") + ) + message(FATAL_ERROR "zephyr_get(... SYSBUILD) requires GLOBAL or LOCAL.") + endif() + else() + set(GET_VAR_SYSBUILD "GLOBAL") + endif() + + if(GET_VAR_REVERSE AND NOT GET_VAR_MERGE) + message(FATAL_ERROR "zephyr_get(... REVERSE) missing a required argument: MERGE") + endif() + + if(NOT DEFINED GET_VAR_VAR) + set(GET_VAR_VAR ${variable}) + endif() + + # Keep current scope variables in internal variables. + # This is needed to properly handle cases where we want to check value against + # environment value or when appending with the MERGE operation. + foreach(var ${GET_VAR_VAR}) + set(current_${var} ${${var}}) + set(${var}) + + if(SYSBUILD) + get_property(sysbuild_name TARGET sysbuild_cache PROPERTY SYSBUILD_NAME) + get_property(sysbuild_main_app TARGET sysbuild_cache PROPERTY SYSBUILD_MAIN_APP) + get_property(sysbuild_${var} TARGET sysbuild_cache PROPERTY ${sysbuild_name}_${var}) + if(NOT DEFINED sysbuild_${var} AND + ("${GET_VAR_SYSBUILD}" STREQUAL "GLOBAL" OR sysbuild_main_app) + ) + get_property(sysbuild_${var} TARGET sysbuild_cache PROPERTY ${var}) + endif() + else() + set(sysbuild_${var}) + endif() + + if(TARGET snippets_scope) + get_property(snippets_${var} TARGET snippets_scope PROPERTY ${var}) + endif() + endforeach() + + set(scopes "sysbuild;CACHE;snippets;ENV;current") + if(GET_VAR_REVERSE) + list(REVERSE scopes) + endif() + foreach(scope IN LISTS scopes) + foreach(var ${GET_VAR_VAR}) + zephyr_var_name("${var}" "${scope}" expansion_var) + if(DEFINED expansion_var) + string(CONFIGURE "${expansion_var}" scope_value) + if(GET_VAR_MERGE) + list(APPEND ${variable} ${scope_value}) + else() + set(${variable} ${scope_value} PARENT_SCOPE) + + if("${scope}" STREQUAL "ENV") + # Set the environment variable in CMake cache, so that a build + # invocation triggering a CMake rerun doesn't rely on the + # environment variable still being available / have identical value. + set(${var} $ENV{${var}} CACHE INTERNAL "Cached environment variable ${var}") + endif() + + if("${scope}" STREQUAL "ENV" AND DEFINED current_${var} + AND NOT "${current_${var}}" STREQUAL "$ENV{${var}}" + ) + # Variable exists as current scoped variable, defined in a CMakeLists.txt + # file, however it is also set in environment. + # This might be a surprise to the user, so warn about it. + message(WARNING "environment variable '${var}' is hiding local " + "variable of same name.\n" + "Environment value (in use): $ENV{${var}}\n" + "Current scope value (hidden): ${current_${var}}\n" + ) + endif() + + return() + endif() + endif() + endforeach() + endforeach() + + if(GET_VAR_MERGE) + if(GET_VAR_REVERSE) + list(REVERSE ${variable}) + list(REMOVE_DUPLICATES ${variable}) + list(REVERSE ${variable}) + else() + list(REMOVE_DUPLICATES ${variable}) + endif() + set(${variable} ${${variable}} PARENT_SCOPE) + endif() +endfunction(zephyr_get variable) + +# Usage: +# zephyr_create_scope() +# +# Create a new scope for creation of scoped variables. +# +# : Name of new scope. +# +function(zephyr_create_scope scope) + if(TARGET ${scope}_scope) + message(FATAL_ERROR "zephyr_create_scope(${scope}) already exists.") + endif() + + add_custom_target(${scope}_scope) +endfunction() + +# Usage: +# zephyr_set( SCOPE [APPEND]) +# +# Zephyr extension of CMake set which allows a variable to be set in a specific +# scope. The scope is used on later zephyr_get() invocation for precedence +# handling when a variable it set in multiple scopes. +# +# : Name of variable +# : Value of variable, multiple values will create a list. +# The SCOPE argument identifies the end of value list. +# SCOPE : Name of scope for the variable +# APPEND : Append values to the already existing variable in +# +function(zephyr_set variable) + cmake_parse_arguments(SET_VAR "APPEND" "SCOPE" "" ${ARGN}) + + zephyr_check_arguments_required_all(zephyr_set SET_VAR SCOPE) + + if(NOT TARGET ${SET_VAR_SCOPE}_scope) + message(FATAL_ERROR "zephyr_set(... SCOPE ${SET_VAR_SCOPE}) doesn't exists.") + endif() + + if(SET_VAR_APPEND) + set(property_args APPEND) + endif() + + set_property(TARGET ${SET_VAR_SCOPE}_scope ${property_args} + PROPERTY ${variable} ${SET_VAR_UNPARSED_ARGUMENTS} + ) +endfunction() + +# Usage: +# zephyr_check_cache( [REQUIRED]) +# +# Check the current CMake cache for and warn the user if the value +# is being modified. +# +# This can be used to ensure the user does not accidentally try to change +# Zephyr build variables, such as: +# - BOARD +# - SHIELD +# +# variable: Name of to check and set, for example BOARD. +# REQUIRED: Optional flag. If specified, then an unset will be +# treated as an error. +# WATCH: Optional flag. If specified, watch the variable and print a warning if +# the variable is later being changed. +# +# Details: +# can be set by 3 sources. +# - Using CMake argument, -D +# - Using an environment variable +# - In the project CMakeLists.txt before `find_package(Zephyr)`. +# +# CLI has the highest precedence, then comes environment variables, +# and then finally CMakeLists.txt. +# +# The value defined on the first CMake invocation will be stored in the CMake +# cache as CACHED_. This allows the Zephyr build system to detect +# when a user reconfigures a sticky variable. +# +# A user can ignore all the precedence rules if the same source is always used +# E.g. always specifies -D= on the command line, +# always has an environment set, or always has a set( foo) +# line in his CMakeLists.txt and avoids mixing sources. +# +# The selected can be accessed through the variable '' in +# following Zephyr CMake code. +# +# If the user tries to change to a new value, then a warning will +# be printed, and the previously cached value (CACHED_) will be +# used, as it has precedence. +# +# Together with the warning, user is informed that in order to change +# the build directory must be cleaned. +# +function(zephyr_check_cache variable) + cmake_parse_arguments(CACHE_VAR "REQUIRED;WATCH" "" "" ${ARGN}) + string(TOLOWER ${variable} variable_text) + string(REPLACE "_" " " variable_text ${variable_text}) + + get_property(cached_value CACHE ${variable} PROPERTY VALUE) + + # If the build has already been configured in an earlier CMake invocation, + # then CACHED_${variable} is set. The CACHED_${variable} setting takes + # precedence over any user or CMakeLists.txt input. + # If we detect that user tries to change the setting, then print a warning + # that a pristine build is needed. + + # If user uses -D=, then cli_argument will hold the new + # value, otherwise cli_argument will hold the existing (old) value. + set(cli_argument ${cached_value}) + if(cli_argument STREQUAL CACHED_${variable}) + # The is no changes to the value. + unset(cli_argument) + endif() + + set(app_cmake_lists ${${variable}}) + if(cached_value STREQUAL ${variable}) + # The app build scripts did not set a default, The variable we are + # reading is the cached value from the CLI + unset(app_cmake_lists) + endif() + + if(DEFINED CACHED_${variable}) + # Warn the user if it looks like he is trying to change the variable + # without cleaning first + if(cli_argument) + if(NOT ((CACHED_${variable} STREQUAL cli_argument) OR (${variable}_DEPRECATED STREQUAL cli_argument))) + message(WARNING "The build directory must be cleaned pristinely when " + "changing ${variable_text},\n" + "Current value=\"${CACHED_${variable}}\", " + "Ignored value=\"${cli_argument}\"") + endif() + endif() + + if(CACHED_${variable}) + set(${variable} ${CACHED_${variable}} PARENT_SCOPE) + set(${variable} ${CACHED_${variable}}) + # This resets the user provided value with previous (working) value. + set(${variable} ${CACHED_${variable}} CACHE STRING "Selected ${variable_text}" FORCE) + else() + unset(${variable} PARENT_SCOPE) + unset(${variable} CACHE) + endif() + else() + zephyr_get(${variable}) + endif() + + if(${CACHE_VAR_REQUIRED} AND NOT DEFINED ${variable}) + message(FATAL_ERROR "${variable} is not being defined on the CMake command-line," + " in the environment or by the app." + ) + endif() + + if(DEFINED ${variable}) + # Store the specified variable in parent scope and the cache + set(${variable} ${${variable}} PARENT_SCOPE) + set(${variable} ${${variable}} CACHE STRING "Selected ${variable_text}") + endif() + set(CACHED_${variable} ${${variable}} CACHE STRING "Selected ${variable_text}") + + if(CACHE_VAR_WATCH) + # The variable is now set to its final value. + zephyr_boilerplate_watch(${variable}) + endif() +endfunction(zephyr_check_cache variable) + + +# Usage: +# zephyr_boilerplate_watch(SOME_BOILERPLATE_VAR) +# +# Inform the build system that SOME_BOILERPLATE_VAR, a variable +# handled in the Zephyr package's boilerplate code, is now fixed and +# should no longer be changed. +# +# This function uses variable_watch() to print a noisy warning +# if the variable is set after it returns. +function(zephyr_boilerplate_watch variable) + variable_watch(${variable} zephyr_variable_set_too_late) +endfunction() + +function(zephyr_variable_set_too_late variable access value current_list_file) + if (access STREQUAL "MODIFIED_ACCESS") + message(WARNING +" + ********************************************************************** + * + * WARNING + * + * CMake variable ${variable} set to \"${value}\" in: + * ${current_list_file} + * + * This is too late to make changes! The change was ignored. + * + * Hint: ${variable} must be set before calling find_package(Zephyr ...). + * + ********************************************************************** +") + endif() +endfunction() + +# Usage: +# zephyr_get_targets( ) +# +# Get build targets for a given directory and sub-directories. +# +# This functions will traverse the build tree, starting from . +# It will read the `BUILDSYSTEM_TARGETS` for each directory in the build tree +# and return the build types matching the list. +# Example of types: OBJECT_LIBRARY, STATIC_LIBRARY, INTERFACE_LIBRARY, UTILITY. +# +# returns a list of targets in matching the required . +function(zephyr_get_targets directory types targets) + get_property(sub_directories DIRECTORY ${directory} PROPERTY SUBDIRECTORIES) + get_property(dir_targets DIRECTORY ${directory} PROPERTY BUILDSYSTEM_TARGETS) + foreach(dir_target ${dir_targets}) + get_property(target_type TARGET ${dir_target} PROPERTY TYPE) + if(${target_type} IN_LIST types) + list(APPEND ${targets} ${dir_target}) + endif() + endforeach() + + foreach(directory ${sub_directories}) + zephyr_get_targets(${directory} "${types}" ${targets}) + endforeach() + set(${targets} ${${targets}} PARENT_SCOPE) +endfunction() + +# Usage: +# test_sysbuild([REQUIRED]) +# +# Test that current sample is invoked through sysbuild. +# +# This function tests that current CMake configure was invoked through sysbuild. +# If CMake configure was not invoked through sysbuild, then a warning is printed +# to the user. The warning can be upgraded to an error by setting `REQUIRED` as +# argument the `test_sysbuild()`. +# +# This function allows samples that are multi-image samples by nature to ensure +# all samples are correctly built together. +function(test_sysbuild) + cmake_parse_arguments(TEST_SYSBUILD "REQUIRED" "" "" ${ARGN}) + + if(TEST_SYSBUILD_REQUIRED) + set(message_mode FATAL_ERROR) + else() + set(message_mode WARNING) + endif() + + if(NOT SYSBUILD) + message(${message_mode} + "Project '${PROJECT_NAME}' is designed for sysbuild.\n" + "For correct user-experiences, please build '${PROJECT_NAME}' " + "using sysbuild." + ) + endif() +endfunction() + +# Usage: +# target_byproducts(TARGET BYPRODUCTS [...]) +# +# Specify additional BYPRODUCTS that this target produces. +# +# This function allows the build system to specify additional byproducts to +# target created with `add_executable()`. When linking an executable the linker +# may produce additional files, like map files. Those files are not known to the +# build system. This function makes it possible to describe such additional +# byproducts in an easy manner. +function(target_byproducts) + cmake_parse_arguments(TB "" "TARGET" "BYPRODUCTS" ${ARGN}) + + if(NOT DEFINED TB_TARGET) + message(FATAL_ERROR "target_byproducts() missing parameter: TARGET ") + endif() + + add_custom_command(TARGET ${TB_TARGET} + POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo "" + BYPRODUCTS ${TB_BYPRODUCTS} + COMMENT "Logical command for additional byproducts on target: ${TB_TARGET}" + ) +endfunction() + +######################################################## +# 4. Devicetree extensions +######################################################## +# 4.1. dt_* +# +# The following methods are for retrieving devicetree information in CMake. +# +# Notes: +# +# - In CMake, we refer to the nodes using the node's path, therefore +# there is no dt_path(...) function for obtaining a node identifier +# like there is in the C devicetree.h API. +# +# - As another difference from the C API, you can generally use an +# alias at the beginning of a path interchangeably with the full +# path to the aliased node in these functions. The usage comments +# will make this clear in each case. + +# Usage: +# dt_nodelabel( NODELABEL

] +# +# Preprocess one or more devicetree source files. The preprocessor +# symbol __DTS__ will be defined. If the preprocessor command fails, a +# fatal error occurs. +# +# Mandatory arguments: +# +# CPP []: path to C preprocessor, followed by any +# additional arguments +# +# SOURCE_FILES : The source files to run the preprocessor on. +# These will, in effect, be concatenated in order +# and used as the preprocessor input. +# +# OUT_FILE : Where to store the preprocessor output. +# +# Optional arguments: +# +# DEPS_FILE : If set, generate a dependency file here. +# +# EXTRA_CPPFLAGS : Additional flags to pass the preprocessor. +# +# INCLUDE_DIRECTORIES : Additional #include file directories. +# +# WORKING_DIRECTORY : where to run the preprocessor. +function(zephyr_dt_preprocess) + set(req_single_args "OUT_FILE") + set(single_args "DEPS_FILE;WORKING_DIRECTORY") + set(req_multi_args "CPP;SOURCE_FILES") + set(multi_args "EXTRA_CPPFLAGS;INCLUDE_DIRECTORIES") + cmake_parse_arguments(DT_PREPROCESS "" "${req_single_args};${single_args}" "${req_multi_args};${multi_args}" ${ARGN}) + + foreach(arg ${req_single_args} ${req_multi_args}) + if(NOT DEFINED DT_PREPROCESS_${arg}) + message(FATAL_ERROR "dt_preprocess() missing required argument: ${arg}") + endif() + endforeach() + + set(include_opts) + foreach(dir ${DT_PREPROCESS_INCLUDE_DIRECTORIES}) + list(APPEND include_opts -isystem ${dir}) + endforeach() + + set(source_opts) + foreach(file ${DT_PREPROCESS_SOURCE_FILES}) + list(APPEND source_opts -include ${file}) + endforeach() + + set(deps_opts) + if(DEFINED DT_PREPROCESS_DEPS_FILE) + list(APPEND deps_opts -MD -MF ${DT_PREPROCESS_DEPS_FILE}) + endif() + + set(workdir_opts) + if(DEFINED DT_PREPROCESS_WORKING_DIRECTORY) + list(APPEND workdir_opts WORKING_DIRECTORY ${DT_PREPROCESS_WORKING_DIRECTORY}) + endif() + + # We are leaving linemarker directives enabled on purpose. This tells + # dtlib where each line actually came from, which improves error + # reporting. + set(preprocess_cmd ${DT_PREPROCESS_CPP} + -x assembler-with-cpp + -nostdinc + ${include_opts} + ${source_opts} + ${NOSYSDEF_CFLAG} + -D__DTS__ + ${DT_PREPROCESS_EXTRA_CPPFLAGS} + -E # Stop after preprocessing + ${deps_opts} + -o ${DT_PREPROCESS_OUT_FILE} + ${ZEPHYR_BASE}/misc/empty_file.c + ${workdir_opts}) + + execute_process(COMMAND ${preprocess_cmd} RESULT_VARIABLE ret) + if(NOT "${ret}" STREQUAL "0") + message(FATAL_ERROR "failed to preprocess devicetree files (error code ${ret}): ${DT_PREPROCESS_SOURCE_FILES}") + endif() +endfunction() + +######################################################## +# 5. Zephyr linker functions +######################################################## +# 5.1. zephyr_linker* +# +# The following methods are for defining linker structure using CMake functions. +# +# This allows Zephyr developers to define linker sections and their content and +# have this configuration rendered into an appropriate linker script based on +# the toolchain in use. +# For example: +# ld linker scripts with GNU ld +# ARM scatter files with ARM linker. +# +# Example usage: +# zephyr_linker_section( +# NAME my_data +# VMA RAM +# LMA FLASH +# ) +# +# and to configure special input sections for the section +# zephyr_linker_section_configure( +# SECTION my_data +# INPUT "my_custom_data" +# KEEP +# ) + + +# Usage: +# zephyr_linker([FORMAT ] +# [ENTRY ] +# ) +# +# Zephyr linker general settings. +# This function specifies general settings for the linker script to be generated. +# +# FORMAT : The output format of the linked executable. +# ENTRY : The code entry symbol. +# +function(zephyr_linker) + set(single_args "ENTRY;FORMAT") + cmake_parse_arguments(LINKER "" "${single_args}" "" ${ARGN}) + + if(LINKER_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_linker(${ARGV0} ...) given unknown " + "arguments: ${LINKER_UNPARSED_ARGUMENTS}" + ) + endif() + + if(DEFINED LINKER_FORMAT) + get_property(format_defined TARGET linker PROPERTY FORMAT SET) + if(format_defined) + message(FATAL_ERROR "zephyr_linker(FORMAT ...) already configured.") + else() + set_property(TARGET linker PROPERTY FORMAT ${LINKER_FORMAT}) + endif() + endif() + + if(DEFINED LINKER_ENTRY) + get_property(entry_defined TARGET linker PROPERTY ENTRY SET) + if(entry_defined) + message(FATAL_ERROR "zephyr_linker(ENTRY ...) already configured.") + else() + set_property(TARGET linker PROPERTY ENTRY ${LINKER_ENTRY}) + endif() + endif() +endfunction() + +# Usage: +# zephyr_linker_memory(NAME START
SIZE FLAGS ) +# +# Zephyr linker memory. +# This function specifies a memory region for the platform in use. +# +# Note: +# This function should generally be called with values obtained from +# devicetree or Kconfig. +# +# NAME : Name of the memory region, for example FLASH. +# START
: Start address of the memory region. +# Start address can be given as decimal or hex value. +# SIZE : Size of the memory region. +# Size can be given as decimal value, hex value, or decimal with postfix k or m. +# All the following are valid values: +# 1048576, 0x10000, 1024k, 1024K, 1m, and 1M. +# FLAGS : Flags describing properties of the memory region. +# Currently supported: +# r: Read-only region +# w: Read-write region +# x: Executable region +# The flags r and x, or w and x may be combined like: rx, wx. +function(zephyr_linker_memory) + set(single_args "FLAGS;NAME;SIZE;START") + cmake_parse_arguments(MEMORY "" "${single_args}" "" ${ARGN}) + + if(MEMORY_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) given unknown " + "arguments: ${MEMORY_UNPARSED_ARGUMENTS}" + ) + endif() + + foreach(arg ${single_args}) + if(NOT DEFINED MEMORY_${arg}) + message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) missing required " + "argument: ${arg}" + ) + endif() + endforeach() + + set(MEMORY) + zephyr_linker_arg_val_list(MEMORY "${single_args}") + + string(REPLACE ";" "\;" MEMORY "${MEMORY}") + set_property(TARGET linker + APPEND PROPERTY MEMORY_REGIONS "{${MEMORY}}" + ) +endfunction() + +# Usage: +# zephyr_linker_memory_ifdef( NAME START
SIZE FLAGS ) +# +# Will create memory region if is enabled. +# +# : Setting to check for True value before invoking +# zephyr_linker_memory() +# +# See zephyr_linker_memory() description for other supported arguments. +# +macro(zephyr_linker_memory_ifdef feature_toggle) + if(${${feature_toggle}}) + zephyr_linker_memory(${ARGN}) + endif() +endmacro() + +# Usage: +# zephyr_linker_dts_section(PATH ) +# +# Zephyr linker devicetree memory section from path. +# +# This function specifies an output section for the platform in use based on its +# devicetree configuration. +# +# The section will only be defined if the devicetree exists and has status okay. +# +# PATH : Devicetree node path. +# +function(zephyr_linker_dts_section) + set(single_args "PATH") + cmake_parse_arguments(DTS_SECTION "" "${single_args}" "" ${ARGN}) + + if(DTS_SECTION_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) given unknown " + "arguments: ${DTS_SECTION_UNPARSED_ARGUMENTS}" + ) + endif() + + if(NOT DEFINED DTS_SECTION_PATH) + message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) missing " + "required argument: PATH" + ) + endif() + + dt_node_exists(exists PATH ${DTS_SECTION_PATH}) + if(NOT ${exists}) + return() + endif() + + dt_prop(name PATH ${DTS_SECTION_PATH} PROPERTY "zephyr,memory-region") + if(NOT DEFINED name) + message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) missing " + "\"zephyr,memory-region\" property" + ) + endif() + zephyr_string(SANITIZE name ${name}) + + dt_reg_addr(addr PATH ${DTS_SECTION_PATH}) + + zephyr_linker_section(NAME ${name} ADDRESS ${addr} VMA ${name} TYPE NOLOAD) + +endfunction() + +# Usage: +# zephyr_linker_dts_memory(PATH FLAGS ) +# zephyr_linker_dts_memory(NODELABEL FLAGS ) +# zephyr_linker_dts_memory(CHOSEN FLAGS ) +# +# Zephyr linker devicetree memory. +# This function specifies a memory region for the platform in use based on its +# devicetree configuration. +# +# The memory will only be defined if the devicetree node or a devicetree node +# matching the nodelabel exists and has status okay. +# +# Only one of PATH, NODELABEL, and CHOSEN parameters may be given. +# +# PATH : Devicetree node identifier. +# NODELABEL